diff -u --recursive --new-file v2.4.6/linux/CREDITS linux/CREDITS
--- v2.4.6/linux/CREDITS	Tue Jul  3 17:08:18 2001
+++ linux/CREDITS	Wed Jul  4 14:41:33 2001
@@ -78,8 +78,8 @@
 D: Unix98 pty support.
 D: APM update to 1.2 spec.
 D: /devfs hacking.
-S: 322 N. Riverside Dr.
-S: Neptune, NJ 07753
+S: 7 Kiwi Loop
+S: Howell, NJ 07731
 S: USA
 
 N: Erik Andersen
@@ -679,6 +679,14 @@
 S: K1N 6Z9
 S: CANADA
 
+N: Jeff Dike
+E: jdike@karaya.com
+W: http://user-mode-linux.sourceforge.net
+D: User mode kernel port
+S: RR1 Box 67C
+S: Deering NH 03244
+S: USA
+
 N: Eddie C. Dost
 E: ecd@skynet.be
 D: Linux/Sparc kernel hacker
@@ -957,6 +965,12 @@
 S: New South Wales, 2121
 S: Australia
 
+N: Carlos E. Gorges 
+E: carlos@techlinux.com.br
+D: fix smp support on cmpci driver
+P: 2048G/EA3C4B19 FF31 33A6 0362 4915 B7EB  E541 17D0 0379 EA3C 4B19
+S: Brazil
+
 N: Dmitry S. Gorodchanin
 E: pgmdsg@ibi.com
 D: RISCom/8 driver, misc kernel fixes.
@@ -1056,6 +1070,11 @@
 S: 2400 AG, Alphen aan den Rijn
 S: The Netherlands
 
+N: Enver Haase
+E: ehaase@inf.fu-berlin.de
+W: http://www.inf.fu-berlin.de/~ehaase
+D: Driver for the Commodore A2232 serial board
+
 N: Bruno Haible
 E: haible@ma2s2.mathematik.uni-karlsruhe.de
 D: SysV FS, shm swapping, memory management fixes
@@ -1269,12 +1288,11 @@
 S: USA
 
 N: Gareth Hughes
-E: gareth@valinux.com
-E: gareth@precisioninsight.com
+E: gareth.hughes@acm.org
 D: Pentium III FXSR, SSE support
-S: 11/187 West Street
-S: Crows Nest NSW 2065
-S: Australia
+D: Author/maintainer of most DRM drivers (especially ATI, MGA)
+D: Core DRM templates, general DRM and 3D-related hacking
+S: No fixed address
 
 N: Kenn Humborg
 E: kenn@wombat.ie
@@ -2253,6 +2271,15 @@
 E: ken@halcyon.com
 D: CDROM driver "sonycd535" (Sony CDU-535/531)
 
+N: Stelian Pop
+E: stelian.pop@fr.alcove.com
+P: 1024D/EDBB6147 7B36 0E07 04BC 11DC A7A0  D3F7 7185 9E7A EDBB 6147
+D: sonypi, meye drivers, mct_u232 usb serial hacks
+S: Alcôve
+S: 153, bd. Anatole France 
+S: 93200 Saint Denis
+S: France
+
 N: Frederic Potter 
 E: fpotter@cirpack.com
 D: Some PCI kernel support
@@ -2349,14 +2376,15 @@
 S: France
 
 N: Rik van Riel
-E: riel@nl.linux.org
-W: http://www.nl.linux.org/~riel/
+E: riel@conectiva.com.br
+W: http://www.surriel.com/
 D: Linux-MM site, Documentation/sysctl/*, swap/mm readaround
 D: clustering contributor, kswapd fixes, random kernel hacker,
-D: nl.linux.org maintainer, minor scheduler additions
-S: IJsselstraat 23a
-S: 9725 GA  Groningen
-S: The Netherlands
+D: nl.linux.org administrator, minor scheduler additions
+S: Conectiva S.A.
+S: R. Tocantins, 89 - Cristo Rei
+S: 80050-430 - Curitiba - Paraná
+S: Brazil
 
 N: Pekka Riikonen
 E: priikone@poseidon.pspt.fi
@@ -2862,6 +2890,7 @@
 N: Petr Vandrovec
 E: vandrove@vc.cvut.cz
 D: Small contributions to ncpfs
+D: Matrox framebuffer driver
 S: Chudenicka 8
 S: 10200 Prague 10, Hostivar
 S: Czech Republic
diff -u --recursive --new-file v2.4.6/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.6/linux/Documentation/Configure.help	Tue Jul  3 17:08:18 2001
+++ linux/Documentation/Configure.help	Fri Jul  6 16:48:50 2001
@@ -8842,6 +8842,18 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called myri_sbus.o.
 
+D-Link 2000-based Gigabit Ethernet support
+CONFIG_DL2K
+  This driver supports D-Link 2000-based gigabit ethernet cards, which
+  includes
+	D-Link DGE-550T Gigabit Ethernet Adapter.
+	D-Link DL2000-based Gigabit Ethernet Adapter.
+
+  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 dl2k.o.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
diff -u --recursive --new-file v2.4.6/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile
--- v2.4.6/linux/Documentation/DocBook/Makefile	Tue Jul  3 17:08:18 2001
+++ linux/Documentation/DocBook/Makefile	Sun Jul  8 13:13:47 2001
@@ -1,7 +1,7 @@
 BOOKS	:= wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
 	   kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
 	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
-	   deviceiobook.sgml procfs-guide.sgml
+	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
 
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -61,6 +61,9 @@
 via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \
 		<via-audio.tmpl >via-audio.sgml
+
+tulip-user.sgml: tulip-user.tmpl
+	$(TOPDIR)/scripts/docgen <$< >$@
 
 sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \
diff -u --recursive --new-file v2.4.6/linux/Documentation/DocBook/via-audio.tmpl linux/Documentation/DocBook/via-audio.tmpl
--- v2.4.6/linux/Documentation/DocBook/via-audio.tmpl	Mon Oct 30 12:24:22 2000
+++ linux/Documentation/DocBook/via-audio.tmpl	Sun Jul  8 13:14:00 2001
@@ -17,7 +17,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2000</year>
+   <year>1999-2001</year>
    <holder>Jeff Garzik</holder>
   </copyright>
 
@@ -149,23 +149,6 @@
      <title>Known Bugs And Assumptions</title>
   <para>
   <variablelist>
-    <varlistentry><term>MMAP support</term>
-    <listitem>
-    <para>
-    	MMAP support is currently missing.  Make sure to
-	test with Quake.
-    </para>
-    </listitem></varlistentry>
-
-    <varlistentry><term>AC97 codec timeout during init</term>
-    <listitem>
-    <para>
-    	A warning message "via82cxxx: timeout while reading AC97
-	codec" is printed during driver initialization.  This
-	message can safely be ignored.
-    </para>
-    </listitem></varlistentry>
-
     <varlistentry><term>Low volume</term>
     <listitem>
     <para>
@@ -198,6 +181,16 @@
   <para>
 	AC97 mixer interface fixes and debugging by Ron Cemer <email>roncemer@gte.net</email>.
   </para>
+  <para>
+	Rui Sousa <email>rui.sousa@conexant.com</email>, for bugfixing
+	MMAP support, and several other notable fixes that resulted from
+	his hard work and testing.
+  </para>
+  <para>
+	Adrian Cox <email>adrian@humboldt.co.uk</email>, for bugfixing
+	MMAP support, and several other notable fixes that resulted from
+	his hard work and testing.
+  </para>
   </chapter>
   
   <chapter id="notes">
@@ -219,7 +212,10 @@
 	and device ids are not examined.
   </para>
   <para>
-	GNU indent formatting options:  -kr -i8 -pcs
+	GNU indent formatting options:
+  <programlisting>
+-kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl
+  </programlisting>
   </para>
   <para>
 	Via has graciously donated e-mail support and source code to help further
@@ -237,6 +233,79 @@
 
   <chapter id="changelog">
       <title>Driver ChangeLog</title>
+
+<sect1 id="version1115"><title>
+Version 1.1.15
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+    Support for variable fragment size and variable fragment number (Rui
+    Sousa)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Fixes for the SPEED, STEREO, CHANNELS, FMT ioctls when in read &
+    write mode (Rui Sousa)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Mmaped sound is now fully functional. (Rui Sousa)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Make sure to enable PCI device before reading any of its PCI
+    config information. (fixes potential hotplug problems)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Clean up code a bit and add more internal function documentation.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    AC97 codec access fixes (Adrian Cox)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Big endian fixes (Adrian Cox)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    MIDI support (Adrian Cox)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Detect and report locked-rate AC97 codecs.  If your hardware only
+    supports 48Khz (locked rate), then your recording/playback software
+    must upsample or downsample accordingly.  The hardware cannot do it.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Use new pci_request_regions and pci_disable_device functions in
+    kernel 2.4.6.
+    </para>
+   </listitem>
+
+  </itemizedlist>
+</sect1>
 
 <sect1 id="version1114"><title>
 Version 1.1.14
diff -u --recursive --new-file v2.4.6/linux/Documentation/README.nsp_cs.eng linux/Documentation/README.nsp_cs.eng
--- v2.4.6/linux/Documentation/README.nsp_cs.eng	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/README.nsp_cs.eng	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,127 @@
+
+         WorkBiT NinjaSCSI-3/32Bi driver for Linux
+
+1. Comment
+ This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3
+(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi
+(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module
+for Linux.
+
+2. My Linux environment
+Linux kernel: 2.4.0 / 2.2.18
+pcmcia-cs:    3.1.24
+gcc:          gcc-2.95.2
+PC card:      I-O data PCSC-F (NinjaSCSI-3)
+              I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi)
+SCSI device:  I-O data CDPS-PX24 (CD-ROM drive)
+              Media Intelligent MMO-640GT (Optical disk drive)
+
+3. Install
+[1] Check your PC card is true "NinjaSCSI-3" card.
+    If you installed pcmcia-cs already, pcmcia reports your card as UNKNOWN
+    card, and write ["WBT", "NinjaSCSI-3", "R1.0"] or some other string to
+    your console or log file.
+    You can also use "cardctl" program (this program is in pcmcia-cs source
+    code) to get more info.
+
+# cat /var/log/messgaes
+...
+Jan  2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1
+Jan  2 03:45:06 lindberg cardmgr[78]:   product info: "WBT", "NinjaSCSI-3", "R1.0"
+...
+# cardctl ident
+Socket 0:
+  no product info available
+Socket 1:
+  product info: "IO DATA", "CBSC16       ", "1"
+
+
+[2] Get Linux kernel source, and extract it to /usr/src.
+    Because NinjaSCSI driver requiers some SCSI header files in Linux kernel
+    source.
+    I recomend rebuilding your kernel. This eliminate some versioning problem.
+$ cd /usr/src
+$ tar -zxvf linux-x.x.x.tar.gz
+$ cd linux
+$ make config
+...
+
+[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory
+    and make & install. This driver requies pcmcia-cs header file.
+$ cd /usr/src
+$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz
+...
+
+[4] Extract this driver's archive somewhere, and edit Makefile, then do make.
+$ tar -zxvf nsp_cs-x.x.tar.gz
+$ cd nsp_cs-x.x
+$ make
+
+[5] Copy nsp_cs.o to suitable plase, like /lib/modules/<Kernel version>/pcmcia/ .
+
+[6] Add these lines to /etc/pcmcia/config .
+    If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file.
+    So, you don't need to edit file. Just copy to /etc/pcmcia/ .
+
+-------------------------------------
+device "nsp_cs"
+  class "scsi" module "nsp_cs"
+
+card "WorkBit NinjaSCSI-3"
+  version "WBT", "NinjaSCSI-3", "R1.0"
+  bind "nsp_cs"
+
+card "WorkBit NinjaSCSI-32Bi (16bit)"
+  version "WORKBIT", "UltraNinja-16", "1"
+  bind "nsp_cs"
+
+# OEM
+card "WorkBit NinjaSCSI-32Bi (16bit) / IO-DATA"
+  version "IO DATA", "CBSC16       ", "1"
+  bind "nsp_cs"
+
+# OEM
+card "WorkBit NinjaSCSI-32Bi (16bit) / KME-1"
+  version "KME    ", "SCSI-CARD-001", "1"
+  bind "nsp_cs"
+card "WorkBit NinjaSCSI-32Bi (16bit) / KME-2"
+  version "KME    ", "SCSI-CARD-002", "1"
+  bind "nsp_cs"
+card "WorkBit NinjaSCSI-32Bi (16bit) / KME-3"
+  version "KME    ", "SCSI-CARD-003", "1"
+  bind "nsp_cs"
+card "WorkBit NinjaSCSI-32Bi (16bit) / KME-4"
+  version "KME    ", "SCSI-CARD-004", "1"
+  bind "nsp_cs"
+-------------------------------------
+
+[7] Boot (or reboot) pcmcia-cs.
+# /etc/rc.d/rc.pcmcia start        (BSD style)
+or
+# /etc/init.d/pcmcia start         (SYSV style)
+
+
+4. History
+See README.nin_cs .
+
+5. Caution
+ If you eject card when doing some operation for your SCSI device or suspend
+your computer, you encount some *BAD* error like disk crash.
+ It works good when I using this driver right way. But I'm not guarantee
+your data. Please backup your data when you use this driver.
+
+6. Known Bugs
+ Some write error occurs when you use slow device.
+
+7. Testing
+ Please send me some reports(bug reports etc..) of this software.
+When you send report, please tell me these or more.
+	card name
+	kernel version
+	your SCSI device name(hard drive, CD-ROM, etc...)
+
+8. Copyright
+ See GPL.
+
+
+2001/02/01 yokota@netlab.is.tsukuba.ac.jp <YOKOTA Hiroshi>
diff -u --recursive --new-file v2.4.6/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt
--- v2.4.6/linux/Documentation/networking/8139too.txt	Mon May  7 14:13:19 2001
+++ linux/Documentation/networking/8139too.txt	Sun Jul  8 13:17:30 2001
@@ -185,6 +185,20 @@
 Change History
 --------------
 
+Version 0.9.18 - July 6, 2001
+
+* Fix race leading to crashes on some machines.
+* Minimize race leading to low performance.
+* Correct interrupt acknowledgement to cover all three
+  relevant Rx events.
+* Add ethtool driver info support.
+* Collect additional driver-internal statistics.
+* Add descriptions for module parameters.
+* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6.
+* Multicast filter big endian fix.
+* Support new PCI PM API added in kernel 2.4.6.
+
+
 Version 0.9.17 - May 7, 2001
 
 * Fix chipset wakeup bug which prevent media connection for 8139B
diff -u --recursive --new-file v2.4.6/linux/Documentation/networking/dl2k.txt linux/Documentation/networking/dl2k.txt
--- v2.4.6/linux/Documentation/networking/dl2k.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/dl2k.txt	Fri Jul  6 16:48:50 2001
@@ -0,0 +1,236 @@
+
+    D-Link DL2000-based Gigabit Ethernet Adapter Installation 
+    for Linux
+    July 5, 2001
+
+Contents
+========
+ - Compatibility List
+ - Quick Install
+ - Compiling the Driver
+ - Installing the Driver
+ - Option parameter
+ - Configuration Script Sample
+ - Troubleshooting
+
+
+Compatiblity List
+=================
+Adapter Support:
+
+D-Link DGE-550T Gigabit Ethernet Adapter.
+D-Link DL2000-based Gigabit Ethernet Adapter.
+
+
+The driver support Linux kernal 2.4.x later. We had tested it 
+on the environments below.
+
+ . Red Hat v6.2 (update to kernel 2.4.4)
+ . Red Hat v7.0 (update to kernel 2.4.4)
+ . Red Hat v7.1 (kernel 2.4.2-2)
+
+
+Quick Install
+=============
+Install linux driver as following command:
+
+1. make all
+2. insmod dl2x.o 
+3. ifconfig eth0 up 10.xxx.xxx.xxx netmask 255.0.0.0
+                    ^^^^^^^^^^^^^^^\        ^^^^^^^^\
+		    		    IP	             NETMASK 
+Now eth0 bring up, you can test it by "ping" or get more information by 
+"ifconfig". If test ok, then continue next step.
+
+4. cp dl2x.o /lib/modules/`uname -r`/kernel/drivers/net
+5. Add the following lines to /etc/modules.conf:
+	alias eth0 dl2x
+6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0 
+   located at /etc/sysconfig/network-scripts or create it manually.
+   [see - Configuration Script Sample]
+7. Driver will automatically load and configure at next boot time.
+
+Compiling the Driver
+====================
+  In Linux, NIC drivers are most commonly configured as loadable modules.
+The approach of building a monolithic kernel has become obsolete. The driver
+can be compiled as part of a monolithic kernel, but is strongly discouraged.
+The remainder of this section assumes the driver is built as a loadable module.
+In the Linux environment, it is a good idea to rebuild the driver from the
+source instead of relying on a precompiled version. This approach provides
+better reliability since a precompiled driver might depend on libraries or
+kernel features that are not present in a given Linux installation.
+
+The 3 files necessary to build Linux device driver are dl2x.c, dl2x.h and
+Makefile. To compile, the Linux installation must include the gcc compiler,
+the kernel source, and the kernel headers. The Linux driver supports Linux
+Kernels 2.4.x. Copy the files to a directory and enter the following command 
+to compile and link the driver:
+
+CD-ROM drive
+------------
+
+[root@XXX /] mkdir cdrom
+[root@XXX /] mount -r -t iso9660 -o conv=auto /dev/cdrom /cdrom
+[root@XXX /] cd root
+[root@XXX /root] mkdir dl2x
+[root@XXX /root] cd dl2x
+[root@XXX dl2x] cp /cdrom/linux/dl2x.tgz /root/dl2x
+[root@XXX dl2x] tar xfvz dl2x.tgz 
+[root@XXX dl2x] make all
+
+Floppy disc drive
+-----------------
+
+[root@XXX /] cd root
+[root@XXX /root] mkdir dl2x
+[root@XXX /root] cd dl2x
+[root@XXX dl2x] mcopy a:/linux/dl2x.tgz /root/dl2x
+[root@XXX dl2x] tar xfvz dl2x.tgz 
+[root@XXX dl2x] make all
+
+Installing the Driver
+=====================
+
+  Manual Installation
+  -------------------
+  Once the driver has been compiled, it must be loaded, enabled, and bound
+  to a protocol stack in order to establish network connectivity. To load a
+  module enter the command:
+
+  insmod dl2x.o
+ 
+
+  or
+
+  insmod dl2x.o <optional parameter>    ; add parameter
+  
+  ===============================================================
+   example: insmod dl2x.o media=100mbps_hd
+   or       insmod dl2x.o media=3
+   or	    insmod dl2x.o media=3 2	; for 2 cards
+  ===============================================================
+
+  Please reference the list of the command line parameters supported by
+  the Linux device driver below.
+
+  The insmod command only loads the driver and gives it a name of the form
+  eth0, eth1, etc. To bring the NIC into an operational state,
+  it is necessary to issue the following command:
+
+  ifconfig eth0 up
+
+  Finally, to bind the driver to the active protocol (e.g., TCP/IP with
+  Linux), enter the following command:
+
+  ifup eth0
+
+  Note that this is meaningful only if the system can find a configuration
+  script that contains the necessary network information. A sample will be
+  given in the next paragraph.
+
+  The commands to unload a driver are as follows:
+
+  ifdown eth0
+  ifconfig eth0 down
+  rmmod dl2x.o
+
+  The following are the commands to list the currently loaded modules and
+  to see the current network configuration.
+
+  lsmod
+  ifconfig
+
+
+  Automated Installation
+  ----------------------
+  This section describes how to install the driver such that it is
+  automatically loaded and configured at boot time. The following description
+  is based on a Red Hat 6.0/7.0 distribution, but it can easily be ported to
+  other distributions as well.
+
+  Red Hat v6.x/v7.x
+  -----------------
+  1. Copy dl2x.o to the network modules directory, typically
+     /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net.
+  2. Locate the boot module configuration file, most commonly modules.conf
+     or conf.modules in the /etc directory. Add the following lines:
+
+     alias ethx dl2x
+     options dl2x <optional parameters>
+
+     where ethx will be eth0 if the NIC is the only ethernet adapter, eth1 if
+     one other ethernet adapter is installed, etc. Refer to the table in the
+     previous section for the list of optional parameters.
+  3. Locate the network configuration scripts, normally the
+     /etc/sysconfig/network-scripts directory, and create a configuration
+     script named ifcfg-ethx that contains network information.
+  4. Note that for most Linux distributions, Red Hat included, a configuration
+     utility with a graphical user interface is provided to perform steps 2
+     and 3 above.
+
+
+Parameter Description
+=====================
+You can install this driver without any addtional parameter. However, if you 
+are going to have extensive functions then it is necessary to set extra 
+parameter. Below is a list of the command line parameters supported by the 
+Linux device
+driver.
+
+mtu=packet_size                 - Specifies the maximum packet size. default
+                                  is 1500.
+
+media=xxxxxxxxx			- Specifies the media type the NIC operates at.
+				  autosense	Autosensing active media.
+				  10mbps_hd 	10Mbps half duplex.
+				  10mbps_fd 	10Mbps full duplex.
+				  100mbps_hd 	100Mbps half duplex.
+				  100mbps_fd 	100Mbps full duplex.
+				  1000mbps_fd	1000Mbps full duplex.
+				  1000mbps_hd	1000Mbps half duplex.
+				  0		Autosensing active media.
+				  1	 	10Mbps half duplex.
+				  2	 	10Mbps full duplex.
+				  3	 	100Mbps half duplex.
+				  4	 	100Mbps full duplex.
+				  5		1000Mbps full duplex.
+				  6		1000Mbps half duplex.
+				  By default, the NIC operates at autosense.
+				  
+vlan=x				- Specifies the VLAN ID. If vlan=0, the  
+				  Virtual Local Area Network (VLAN) function is
+				  disable. 
+				  
+jumbo=x				- Specifies the jumbo frame support. If jumbo=1, 
+				  the NIC accept jumbo frames. By default, this
+				  function is disabled.
+
+Configuration Script Sample
+===========================
+Here is a sample of a simple configuration script:
+
+DEVICE=eth0
+USERCTL=no
+ONBOOT=yes
+POOTPROTO=none
+BROADCAST=207.200.5.255
+NETWORK=207.200.5.0
+NETMASK=255.255.255.0
+IPADDR=207.200.5.2
+
+
+Troubleshooting
+===============
+Q: Couldn't compiler the driver ?
+A1: Copy all necessary files on same current directory. Make sure all files 
+   are Unix file format (no LF). You can use some convertible program conver 
+   it from DOS to UNIX. (Like dos2unix,  UltraEdit-32 ...).
+      
+A2: The default include directory configured in Makefile is 
+    /usr/src/linux/include. If kernel source was not installed, you could 
+    not compile driver. Try to install kernel source, and make sure kernel 
+    source in /usr/src/linux. If there is a copy of header files in 
+    /usr/include, you can try to change the variable "INCLUDEDIR" in Makefile from 
+    /usr/src/linux/include to /usr/include.
+    
diff -u --recursive --new-file v2.4.6/linux/Documentation/networking/multicast.txt linux/Documentation/networking/multicast.txt
--- v2.4.6/linux/Documentation/networking/multicast.txt	Mon Aug  9 10:23:09 1999
+++ linux/Documentation/networking/multicast.txt	Wed Jul  4 11:50:38 2001
@@ -39,11 +39,13 @@
 hp		YES		YES		YES		Hardware
 hp100		YES		YES		YES		Hardware
 ibmtr		NO		NO		NO		N/A
+ioc3-eth	YES		YES		YES		Hardware
 lance		YES		YES		YES		Software(#)
 ne		YES		YES		YES		Hardware
 ni52		<------------------ Buggy ------------------>
 ni65		YES		YES		YES		Software(#)
 seeq		NO		NO		NO		N/A
+sgiseek		<------------------ Buggy ------------------>
 sk_g16		NO		NO		YES		N/A
 smc-ultra	YES		YES		YES		Hardware
 sunlance	YES		YES		YES		Hardware
diff -u --recursive --new-file v2.4.6/linux/Documentation/sonypi.txt linux/Documentation/sonypi.txt
--- v2.4.6/linux/Documentation/sonypi.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sonypi.txt	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,70 @@
+Sony Programmable I/O Control Device Driver Readme
+--------------------------------------------------
+	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+	Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+	Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
+
+This driver enables access to the Sony Programmable I/O Control Device which
+can be found in many (all ?) Sony Vaio laptops.
+
+It will give access (through a user space utility) to some events those laptops
+generate, like:
+	- jogdial events (the small wheel on the side of Vaios)
+	- capture button events (only on Vaio Picturebook series)
+	- Fn keys
+	- bluetooth button (only on C1VR model)
+
+Those events (see linux/sonypi.h) can be polled using the character device node
+/dev/sonypi (major 10, minor auto allocated or specified as a option).
+
+A simple daemon which translates the jogdial movements into mouse wheel events
+can be downloaded at: <http://www.alcove-labs.org/en/software/sonypi/>
+
+This driver supports also some ioctl commands for setting the LCD screen
+brightness (some more commands may be added in the future).
+
+This driver can also be used to set the camera controls on Picturebook series
+(brightness, contrast etc), and is used by the video4linux driver for the 
+Motion Eye camera.
+
+Please note that this driver was created by reverse engineering the Windows
+driver and the ACPI BIOS, because Sony doesn't agree to release any programming
+specs for its laptops. If someone convinces them to do so, drop me a note.
+
+Module options:
+---------------
+
+	minor: 		minor number of the misc device /dev/sonypi, 
+			default is -1 (automatic allocation, see /proc/misc
+			or kernel logs)
+
+	camera:		if you have a PictureBook series Vaio (with the
+			integrated MotionEye camera), set this parameter to 1
+			in order to let the driver access to the camera
+
+	fnkeyinit:	on some Vaios (C1VE, C1VR etc), the Fn key events don't
+			get enabled unless you set this parameter to 1
+
+	verbose:	print unknown events from the sonypi device
+
+Module use:
+-----------
+
+In order to automatically load the sonypi module on use, you can put those
+lines in your /etc/modules.conf file:
+
+	alias char-major-10-250 sonypi
+	options sonypi minor=250 fnkeyinit=1
+
+This supposes the use of minor 250 for the sonypi device:
+
+	# mknod /dev/sonypi c 10 250
+
+Bugs:
+-----
+
+	- since all development was done by reverse engineering, there is
+	  _absolutely no guarantee_ that this driver will not crash your
+	  laptop. Permanently.
diff -u --recursive --new-file v2.4.6/linux/Documentation/sound/CMI8338 linux/Documentation/sound/CMI8338
--- v2.4.6/linux/Documentation/sound/CMI8338	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/sound/CMI8338	Wed Jul  4 11:50:38 2001
@@ -8,59 +8,80 @@
 On-board C-Media chips
 
 
-WHAT'S NEW
+STEPS TO BUILD DRIVER
 ================================================================================
 
-  1. Support modem interface for 8738. (select in kernel configuration)
-  2. Enable S/PDIF-in to S/PDIF-out (S/PDIF loop).
-  3. Enable 4 channels analog duplicate mode on 3 jack or 4 jack
-     configuration.
+  1. Backup the Config.in and Makefile in the sound driver directory
+     (/usr/src/linux/driver/sound).
+     The Configure.help provide help when you config driver in step
+     4, please backup the original one (/usr/src/linux/Document) and
+     copy this file.
+     The cmpci is document for the driver in detail, please copy it
+     to /usr/src/linux/Document/sound so you can refer it. Backup if
+     there is already one.
 
+  2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
+     directory.
 
-   Be aware: C-Media Electronics Inc. is basically an IC design house,
-   and whose development of software drivers is mainly for use by its OEM
-   customers in their products. C-Media Electronics Inc. itself does not
-   manufacture end-user products, such as PC or sound cards, so it can
-   not fully control the drivers provided to consumers. Drivers provided
-   at this site, therefore, MAY NOT BE APPLICABLE to all sound cards.
-   Drivers you download from this site may function well at certain
-   situation, but C-Media Electronics Inc. does not give any guarantee or
-   assurances. Please be aware that these drivers might cause some
-   technical difficulties when installed
+  3. Change directory to /usr/src/linux
 
+  4. Config cm8338 driver by 'make menuconfig', 'make config' or
+     'make xconfig' command.
 
-1. Config cm8338 driver by 'make menuconfig' or 'make config' command.
+  5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
+     driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
+     For driver option, please refer 'DRIVER PARAMETER'
 
-2. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
+  6. Compile the kernel if necessary.
 
-3. Compile the kernel if necessary.
+  7. Compile the modules by 'make modules'.
 
-4. Compile the modules by 'make modules'.
+  8. Install the modules by 'make modules_install'
 
-5. Install the modules by 'make modules_install'
 
-6. Before first time to run the driver, create module dependency by 'depmod -a'
+INSTALL DRIVER
+================================================================================
+
+  1. Before first time to run the driver, create module dependency by
+     'depmod -a'
+
+  2. To install the driver manually, enter 'modprobe cmpci'.
+
+  3. Driver installation for various distributions:
 
-7. To install the driver, enter 'modprobe cmpci'.
+    a. Slackware 4.0
+       Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
+       file.so you can start the driver automatically each time booting.
 
+    b. Caldera OpenLinux 2.2
+       Use LISA to load the cmpci module.
 
-DRIVER PARAMETERS
+    c. RedHat 6.0 and S.u.S.E. 6.1
+       Add following command in /etc/conf.modules:
+
+       alias sound cmpci
+
+	also visit http://www.cmedia.com.tw for installation instruction.
+
+DRIVER PARAMETER
 ================================================================================
 
   Some functions for the cm8738 can be configured in Kernel Configuration
   or modules parameters. Set these parameters to 1 to enable.
 
+  mpu_io:	I/O ports base for MPU-401, 0 if disabled.
+  fm_io:	I/O ports base for OPL-3, 0 if disabled.
+  spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
+		CD-ROM or DVD-ROM.
   spdif_loop:   Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
                 directly.
-  four_ch:      Enable 4 channels mode, rear-out or line-in will output
-                the same as line-out.
-  rear_out:     Enable this if you have independent rear-out jacket on
-                your sound card, otherwise line-in will be used as
+  speakers:     Number of speakers used.
+  use_line_as_rear:Enable this if you want to use line-in as
                 rear-out.
+  use_line_as_bass:Enable this if you want to use line-in as
+                bass-out.
   modem:	You will need to set this parameter if you want to use
 		the HSP modem. You need install the pctel.o, the modem
 		driver itself.
-
-  (You will need to get the pctel driver (binary only) and the support for
-  this option from the CMI site. It is not included in the Linux kernel 
-  proper as it is non-free).
+  joystick:	Enable joystick. You will need to install Linux joystick
+		driver.
diff -u --recursive --new-file v2.4.6/linux/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt
--- v2.4.6/linux/Documentation/usb/philips.txt	Tue May 22 10:25:36 2001
+++ linux/Documentation/usb/philips.txt	Wed Jul  4 11:50:38 2001
@@ -34,6 +34,10 @@
    specificly, red and blue are swapped), try palette=bgr24 or
    palette=rgb24.
 
+   Only the native yuv420/yuv420p format is supported by the in kernel driver. 
+   If you want to use other formats with in-kernel conversion download the
+   driver from the URL given. [Alan]
+
 fbufs
    This paramter specifies the number of internal buffers to use for storing 
    frames from the cam. This will help if the process that reads images from 
diff -u --recursive --new-file v2.4.6/linux/Documentation/video4linux/Zoran linux/Documentation/video4linux/Zoran
--- v2.4.6/linux/Documentation/video4linux/Zoran	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/Zoran	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,517 @@
+DC10/DC10plus/LML33/Buz  Driver for Linux
+=========================================
+
+by Rainer Johanni <Rainer@Johanni.de> (for Iomega Buz Driver)
+
+Adapted for DC10/DC10plus by Wolfgang Scherr <scherr@net4you.net>
+
+Further changes for DC10/DC10plus and LML33 cards by
+Serguei Miridonov <mirsev@cicese.mx>
+
+Current homepage: http://www.cicese.mx/~mirsev/Linux/DC10plus/
+Current maintainer: Serguei Miridonov <mirsev@cicese.mx>
+
+  This is a driver for DC10plus capture cards from Pinnacle Systems
+  Inc., LML33 cards from Linux Media Labs and Buz from Iomega.
+  It also works with many old Miro DC10 cards with SAA7110A TV decoder
+  and ADV7176 TV encoder (please, make sure that your card has these
+  chips, otherwise the driver will not work).
+
+  The driver is Video4Linux compliant and contains extensions to
+  provide hardware support for full motion MJPEG compression and
+  decompression. Since this driver is a derivative from the driver for
+  Buz Iomega cards written by Dr. Rainer Johanni,
+  http://www.johanni.de/munich-vision/buz/ they both have compatible
+  API. I hope that this API will become a part of V4L standard.
+
+Copyright: This driver is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License. Please,
+check http://www.gnu.org/ for details.
+
+No warranty: This software is provided on AN "AS-IS" basis WITHOUT
+WARRANTY OF ANY KIND. YOU USE IT AT YOUR OWN RISK.
+
+
+
+CONTENTS
+~~~~~~~~
+
+Supported Formats
+Hardware compression
+Compiling and Loading the Driver
+Driver Options
+Tested applications
+Programming interface
+Features for testing
+Mailing lists
+Bug Reports
+
+
+Supported Formats
+=================
+
+Card:              DC10/DC10plus             LML33/Buz
+
+TV standard:       NTSC/PAL/SECAM(*)         NTSC/PAL
+
+Format:            Square pixel              CCIR.601
+                   640x480 NTSC              720x480 NTSC
+                   768x576 PAL/SECAM(*)      720x576 PAL
+
+Frame rates: 30 frames/60 fields per second NTSC
+             25 frames/50 fields per second PAL/SECAM(*)
+
+(*) - SECAM is supported for input only in DC10/DC10plus cards. The
+output of the recorded SECAM video stream will be in PAL standard.
+Also, please, note that monitoring of the SECAM input signal at the
+DC10/DC10plus analog output may not be available. Please, use
+appropriate application like XawTV to watch full color SECAM video at
+the card input.
+
+Hardware compression
+====================
+
+Since the card provides hardware compression, even low end machines can
+be successfully used for movie capture and playback. I'm testing the
+driver with with 2.2.16 kernel running on 233 MHz Pentium MMX with 64M
+RAM on 430TX motherboard and with 10GB IDE drive from Western Digital
+Corp.
+
+On one test run with DC10plus card I've got 0 frames dropped during
+about 20 minutes of full motion NTSC (I live in Mexico) video capture
+with fully synchronized audio. The command was
+
+  lavrec -fa -in -d1 -l -1 -q30 -w /dos/g/capture/Linux/test%03d.avi
+
+for recording, and
+
+  lavplay -n128 /dos/g/capture/Linux/test*.avi
+
+for playback. (See lavtools distribution for more information).
+
+Typical run of similar test can provide as few as 6-8 dropped frames per
+half of an hour. You mileage may vary, though.
+
+Compiling and Loading the Driver
+================================
+
+You should run a 2.2.x kernel in order to use this driver. The driver
+was also tested with 2.4-test6 kernel, so hopefully it will work
+with 2.4 kernels too.
+
+I would recommend to use only official kernels from www.kernel.org and
+its mirrors. Kernels supplied with some Linux distributions may be
+patched in some way to meet specific needs of particular Linux
+distributor and could be incompatible with this driver. As a driver
+maintainer, I am not able to follow every unofficial kernel release,
+and no unofficial kernels will be supported.
+
+Besides the files in this directory, the driver needs the 'videodev'
+and the 'i2c' module from the Linux kernel (i2c-old for 2.4 kernels).
+In order to get these modules available, enable module support for
+VIDEODEV and BTTV (which implies i2c) in your 2.2.x kernel
+configuration. You will find these devices in the menu "Character
+Devices" in your Kernel Configuration.
+
+In newer kernels (2.4) instead of BTTV you should enable support for
+Iomega Buz cards and for Zoran 36060/36067 chipset. This will include
+i2c or i2c-old modules and Buz/LML33 driver. However, instead of
+modules for Buz/LML33 driver from the kernel, use modules from _this_
+driver.
+
+To compile the driver, just type make.
+
+Before you load the driver you must have a video device at major device
+node 81. If you don't have it yet, do the following (as root!):
+
+cd /dev
+mknod video0 c 81 0
+ln -s video0 video
+
+If you have more than one card, add more nodes in /dev directory:
+
+mknod video1 c 81 1
+mknod video2 c 81 2
+...
+
+The driver should operate properly with several cards. It was tested
+with one DC10plus and one LML33 cards installed together and the driver
+correctly identifies both cards and works with both of them.
+
+Currently the driver does not support LML33 and Buz cards installed
+together in the same system. This will be fixed in future versions.
+
+Edit the 'update' script if you want to give the driver special options
+(see below for options descriptions) and then type (as root)
+
+./update <card_list>
+
+to insert all necessary modules into the kernel. <card_list> is a list of
+cards installed in your system separated by white space. Supported cards 
+are dc10, dc10plus, lml33, and buz. For example, if you have both dc10plus
+and lml33 cards, please type
+
+./update dc10 lml33
+
+If you want to make full use of the Video for Linux _uncompressed_
+grabbing facilities, you must either
+
+- obtain and install the "big_physarea patch" for your kernel and
+  set aside the necessary memory during boot time. There seem to be
+  several versions of this patch against various kernel versions
+  floating around in the net, you may obtain one e.g. from:
+  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You
+  also have to compile your driver AFTER installing that patch in order
+  to get it working
+
+  or
+
+- start your kernel with the mem=xxx option, where xxx is your
+  real memory minus the memory needed for the buffers.
+  For doing this add an entry in lilo.conf (if you use lilo):
+    append "mem=xxxM"
+  or add a line in your linux.par file (if you use loadlin):
+    mem=xxxM
+
+The second method is by far easier, however it is dangerous if more
+than one driver at a time has the idea to use the memory leftover by
+setting the mem=xxx parameter below the actual memory size.
+
+Read also below how to use this memory!
+
+
+  If you use only MJPEG compressed capture provided by the driver, you
+  should not need large memory areas for DMA. In this case, you will be
+  able to capture and playback movies with lavtools, however you will
+  not be able to use capture features of XawTV and other similar
+  programs (you can still watch video on the screen).
+
+
+
+Driver Options
+==============
+
+You are able to customize the behavior of the driver by giving
+it some options at start time.
+
+default_input, default_norm
+---------------------------
+
+As soon as the driver is loaded, the Buz samples video signals
+from one of its input ports and displays it on its output.
+The driver uses the Composite Input and the video norm PAL for this.
+If you want to change this default behavior, set default_input=1
+(for S-VHS input) or default_norm=1 for NTSC or default_norm=2
+for SECAM (DC10/DC10plus only).
+
+lock_norm
+---------
+
+This option was introduced to disable norm (TV standard) change by some
+not well behaving programs. For example, if you have some application
+which was written by somebody who lives in a country with PAL standard,
+this program may not have NTSC option and may always try to set the
+driver to PAL. In this case, you may load the driver with
+default_norm=1 and lock_norm=1 and the card will be forced to work in
+NTSC standard only.
+
+  Options:
+  
+  lock_norm=0   default, TV standard change is enabled;
+  lock_norm=1   TV standard change is disabled but the driver
+                will not notify the application about any error;
+  lock_norm=2   TV standard change is disabled and the driver
+                will notify the program that TV standards other
+                than set by default_norm=X option are not 
+                supported.
+
+pass_through
+------------
+
+When the driver is not in use (device is not opened by any program) and
+pass_through=0 (default) the driver will set the TV encoder to produce
+color bar signal at the output. If the driver was loaded with
+pass_through=1, the color bar will be disabled and input signal will be
+sent to the output even if the driver not in use. If you have LML33 card
+and wish the color bar signal at the output, you will also need to set
+lml33dpath=1 (please, see next section).
+
+lml33dpath
+----------
+
+LML33 card normally (lml33dpath=0) connects its output to the input
+using analog switch. Additionally, it also allows real-time monitoring
+of digitized video using TV monitor connected to the output. This
+"digital path" option can be enabled setting lml33dpath=1. In this
+mode, the input is connected only to the TV decoder, digital video data
+is sent via internal video bus to the TV encoder and resulting analog
+signal is sent to the output. This mode could be very useful for testing and
+picture adjustment while watching video at the TV monitor connected to
+the output. However, because of lack of 75 ohm terminating resistors at
+TV decoder input, the signal will suffer serious distortions.
+
+# These distortions could be eliminated by soldering two 75 ohm resistors
+# in LML33 card: in parallel to capacitors C73 and C82 (see schematics of
+# H33 board available at www.linuxmedialabs.com and www.zoran.com). Be
+# aware, however, that doing so will void card warranty and the card,
+# after this change, must always be used with loading option lml33dpath=1.
+# 
+# WARNING: I DID NOT TRY THIS CARD CHANGE YET, THIS IS JUST AN ASSUMPTION
+# AND I WILL NOT BE RESPONSIBLE FOR ANY DAMAGE ASSOCIATED WITH THIS
+# CHANGE. IF YOU WISH TO TRY IT, DO IT AT YOUR OWN RISK.
+
+Please, note that DC10/DC10plus cards always use "digital path" for
+signal monitoring. Its input and output are both properly terminated
+and the digitized signal quality does not depend on the connection of
+the output load.
+
+
+v4l_nbufs, v4l_bufsize
+----------------------
+
+In order to make to make full use of the Video for Linux uncompressed
+picture grabbing facilities of the driver (which are needed by many
+Video for Linux applications), the driver needs a set of physically
+contiguous buffers for grabbing. These parameters determine how many
+buffers of which size the driver will allocate at open (the open will
+fail if it is unable to do so!).
+
+These values do not affect the MJPEG grabbing facilities of the driver,
+they are needed for uncompressed image grabbing only!!!
+
+v4l_nbufs is the number of buffers to allocate, a value of 2 (the default)
+should be sufficient in almost all cases. Only special applications
+(streaming captures) will need more buffers and then mostly the
+MJPEG capturing features of the Buz will be more appropriate.
+So leave this parameter at it's default unless you know what you do.
+
+The things for v4l_bufsize are more complicated: v4l_bufsize is set by
+default to 128 [KB] which is the maximum amount of physically
+contiguous memory Linux is able to allocate without kernel changes.
+This is sufficient for grabbing 24 bit color images up to sizes of
+approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072).
+
+In order to be able to capture bigger images you have either to
+- obtain and install the "big_physarea patch" and set aside
+  the necessary memory during boot time or
+- start your kernel with the mem=xxx option, where xxx is your
+  real memory minus the memory needed for the buffers.
+In that case, useful settings for v4l_bufsize are
+- 1296 [Kb] for grabbing 24 bit images of max size 768*576
+- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!)
+You may reduce these numbers accordingly if you know you are only
+grabbing 720 pixels wide images or NTSC images (max height 480).
+
+In some cases it may happen that Linux isn't even able to obtain
+the default 128 KB buffers. If you don't need uncompressed image
+grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4)
+in order to be able to open the video device.
+
+triton, natoma
+--------------
+
+The driver tries to detect if you have a triton or natoma chipset
+in order to take special measures for these chipsets.
+If this detection fails but you are sure you have such a chipset,
+set the corresponding variable to 1.
+This is a very special option and may go away in the future.
+
+
+Tested applications
+===================
+
+  XawTV         to watch video on your computer monitor.
+
+  kwintv        the same (you might need to use option lock_norm=1).
+  
+  lavtools      To record and playback AVI or Quicktime files. Note: you
+                will need patched version, lavtools-1.2p2 to support new
+                features of this driver. Please visit driver homepage for
+                more info.
+
+  Broadcast2000 reportedly (I didn't try that) can accept movies recorded
+                by lavrec in Quicktime format for editing and then edited
+                movie can be played back by lavplay program.
+
+  MainActor 3.5x also can accept movies recorded by lavrec for editing.
+
+
+The driver can to be used by two programs at the same time
+(please, see warning note below regarding this feature). Using XawTV
+you can watch what you are recording or playing back with lavtools.
+I've tested the following sequence and it worked for me:
+
+* start xawtv and switch inputs, TV standards, and adjust video
+  (contrast, saturation, etc.). You may also run your favorite
+  audio mixer application to adjust audio inputs.
+
+* run lavrec with options: 
+
+    -i<set your input and norm here> (to choose proper input
+                                      and TV standard)
+
+    -l -1  (to use audio mixer settings)
+
+    Other lavrec option can be added at your choice.
+
+* watch the movie in xawtv window while recording it as AVI or
+  Quicktime file.
+
+* when recording is finished, run lavplay or xlav and watch your
+  clip in xawtv window.
+
+* Note: you should not quit xawtv during recording or playing back.
+  If you quit xawtv during recording or playback, another lavtools
+  program will stop and may even crash.
+
+I'm not sure that the same will work for you. You can try but,
+please, be careful.
+
+WARNING! This is an experimental feature and I'm not sure if it will be
+supported in the future. The original driver was not designed to be
+used like this and it has no protection against any interference
+between two running programs. THEREFORE, IT IS POTENTIALLY DANGEROUS
+AND SINCE THE DRIVER OPERATES IN KERNEL SPACE, USING THIS FEATURE MAY
+CRASH YOUR ENTIRE SYSTEM.
+
+
+Programming interface
+=====================
+
+This driver should be fully compliant to Video for Linux, so all
+tools working with Video for Linux should work with (hopefully)
+no problems.
+
+A description of the Video for Linux programming interface can be found at:
+http://roadrunner.swansea.linux.org.uk/v4lapi.shtml
+
+Besides the Video for Linux interface, the driver has a "proprietary"
+interface for accessing the Buz's MJPEG capture and playback facilities.
+
+For a full description of all members and ioctls see "zoran.h" (used to
+be buz.h or dc10.h in previous versions, so, please, update your
+programs accordingly).
+
+The ioctls for that interface are as follows:
+
+BUZIOC_G_PARAMS
+BUZIOC_S_PARAMS
+
+Get and set the parameters of the buz. The user should always do a
+BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default
+settings, change what he likes and then make a BUZIOC_S_PARAMS call.
+
+BUZIOC_REQBUFS
+
+Before being able to capture/playback, the user has to request
+the buffers he is wanting to use. Fill the structure
+zoran_requestbuffers with the size (recommended: 256*1024) and
+the number (recommended 32 up to 256). There are no such restrictions
+as for the Video for Linux buffers, you should LEAVE SUFFICIENT
+MEMORY for your system however, else strange things will happen ....
+On return, the zoran_requestbuffers structure contains number and
+size of the actually allocated buffers.
+You should use these numbers for doing a mmap of the buffers
+into the user space.
+The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap
+maps the MJPEG buffer instead of the V4L buffers.
+
+BUZIOC_QBUF_CAPT
+BUZIOC_QBUF_PLAY
+
+Queue a buffer for capture or playback. The first call also starts
+streaming capture. When streaming capture is going on, you may
+only queue further buffers or issue syncs until streaming
+capture is switched off again with a argument of -1 to
+a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl.
+
+BUZIOC_SYNC
+
+Issue this ioctl when all buffers are queued. This ioctl will
+block until the first buffer becomes free for saving its
+data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY).
+
+BUZIOC_G_STATUS
+
+Get the status of the input lines (video source connected/norm).
+This ioctl may be subject to change.
+
+For programming example, please, look at lavrec.c and lavplay.c code in
+lavtools-1.2p2 package (URL: http://www.cicese.mx/~mirsev/DC10plus/)
+and the 'examples' directory in the original Buz driver distribution.
+
+Additional notes for software developers:
+
+   The driver returns maxwidth and maxheight parameters according to
+   the current TV standard (norm). Therefore, the software which
+   communicates with the driver and "asks" for these parameters should
+   first set the correct norm. Well, it seems logically correct: TV
+   standard is "more constant" for current country than geometry
+   settings of a variety of TV capture cards which may work in ITU or
+   square pixel format. Remember that users now can lock the norm to
+   avoid any ambiguity.
+
+Features for testing
+====================
+
+When loaded, the driver creates a /proc/zoranX entry for each card:
+using 'cat /proc/zoran0' for your first card you can see the contents
+of ZR36057/67 chip registers. It is also possible to modify the
+contents of some registers directly. WARNING: modified contents is not
+stored in the driver memory, if you restart any program which uses this
+driver or even change position or cause redraw of a window of xawtv or
+other program, the original registers contents will be restored by the
+driver. However, it can be used to change ZR36067 registers on the fly
+for fine tuning and then to include these changes into driver code.
+This feature is very limited and still requires some documentation.
+However, if you are impatient, look at zoran_procfs.c code and
+(IMPORTANT!) read ZR36057/67 manual. To set TopField bit, for example,
+you need to type as root:
+
+echo TopField=1 > /proc/zoranX # change X to 0 for your first card,
+                               # 1 for second and so on...
+
+If you use this feature and have found some interesting result, please, let
+me know.
+
+Mailing lists
+=============
+
+There are two mailing lists available to discuss application issues and
+suggest driver improvements:
+
+1. A mailing list buz-linux was set up to discuss Iomega Buz driver.
+Since this driver is derivative of that driver, you can also post your
+questions and suggestions there. Subscribe with a message (with
+"subscribe" in the subject) to  buz-linux-subscribe@webmages.com.
+Unsubscribe with a message (with "unsubscribe" in the subject) to
+buz-linux-unsubscribe@webmages.com. The mailing list archive can be
+found at http://buz.webmages.com/list/. 
+
+2. Video4Linux mailing list is set for more general discussions related
+to uncompressed video capture, V4L and V4L2 API, many Video4Linux
+applications, etc. to subscribe to this mailing list, please, visit
+https://listman.redhat.com/mailman/listinfo/video4linux-list
+
+Bug Reports
+===========
+
+If you have found a bug, please, do the following:
+
+1. Edit first line of zoran.c file and set DEBUGLEVEL to 3;
+2. Recompile the driver and install it running update script
+   in the driver directory;
+3. Run the application(s) which you used when you had found a
+   suspisious behavior;
+4. When application stops, look at you /var/log/messages file
+   (or whatever file you use to log kernel messages) and copy
+   all lines related to the driver activity to a separate file
+   in the same order of their appearence in your log file.
+5. Mail a message to <mirsev@cicese.mx> with a subject
+   "Linux DC10(plus)/LML33/Buz driver bug report" with a detailed
+   description of your problem, kernel version, application name and
+   attach that file with kernel messages as plain text (please, don't
+   attach it using base64, uuencode, or any other encoding).
+   
+   If you have a Buz card, please, also mail the same message to
+   Wolfgang Scherr <scherr@net4you.net>
diff -u --recursive --new-file v2.4.6/linux/Documentation/video4linux/meye.txt linux/Documentation/video4linux/meye.txt
--- v2.4.6/linux/Documentation/video4linux/meye.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/meye.txt	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,102 @@
+Vaio Picturebook Motion Eye Camera Driver Readme
+------------------------------------------------
+	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
+
+This driver enable the use of video4linux compatible applications with the
+Motion Eye camera.
+
+It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
+
+Grabbing is supported in packed YUV colorspace only.
+
+MJPEG hardware grabbing is supported via a private API (see below).
+
+Module options:
+---------------
+
+	gbuffers:	number of capture buffers, default is 2 (32 max)
+
+	gbufsize:	size of each capture buffer, default is 614400
+
+	video_nr:	video device to register (0 = /dev/video0, etc)
+
+Module use:
+-----------
+
+In order to automatically load the meye module on use, you can put those lines
+in your /etc/modules.conf file:
+
+	alias char-major-81 videodev
+	alias char-major-81-0 meye
+	options meye gbuffers=32
+
+Usage:
+------
+
+	xawtv >= 3.49 (<http://bytesex.org/xawtv/>)
+		for display and uncompressed video capture:
+
+			xawtv -c /dev/video0 -geometry 640x480
+				or
+			xawtv -c /dev/video0 -geometry 320x240
+
+	motioneye (<http://www.alcove-labs.org/en/software/meye/>)
+		for getting ppm or jpg snapshots, mjpeg video
+
+Private API:
+------------
+
+	The driver supports frame grabbing with the video4linux API, so
+	all video4linux tools (like xawtv) should work with this driver.
+
+	Besides the video4linux interface, the driver has a private interface
+	for accessing the Motion Eye extended parameters (camera sharpness,
+	agc, video framerate), the shapshot and the MJPEG capture facilities.
+
+	This interface consists of several ioctls (prototypes and structures
+	can be found in include/linux/meye.h):
+
+	MEYEIOC_G_PARAMS
+	MEYEIOC_S_PARAMS
+		Get and set the extended parameters of the motion eye camera.
+		The user should always query the current parameters with
+		MEYEIOC_G_PARAMS, change what he likes and then issue the
+		MEYEIOC_S_PARAMS call (checking for -EINVAL). The extended
+		parameters are described by the meye_params structure.
+
+
+	MEYEIOC_QBUF_CAPT
+		Queue a buffer for capture (the buffers must have been
+		obtained with a VIDIOCGMBUF call and mmap'ed by the
+		application). The argument to MEYEIOC_QBUF_CAPT is the
+		buffer number to queue (or -1 to end capture). The first
+		call to MEYEIOC_QBUF_CAPT starts the streaming capture.
+
+	MEYEIOC_SYNC
+		Takes as an argument the buffer number you want to sync.
+		This ioctl blocks untils the buffer is filled and ready
+		for the application to use. It returns the buffer size.
+
+	MEYEIOC_STILLCAPT
+	MEYEIOC_STILLJCAPT
+		Takes a snapshot in an uncompressed or compressed jpeg format.
+		This ioctl blocks until the snapshot is done and returns (for
+		jpeg snapshot) the size of the image. The image data is 
+		available from the first mmap'ed buffer.
+
+	Look at the 'motioneye' application code for an actual example.
+
+Bugs / Todo:
+------------
+
+	- overlay output is not supported (although the camera is capable of).
+	  	(it should not be too hard to to it, provided we found how...)
+		
+	- mjpeg hardware playback doesn't work (depends on overlay...)
+
+	- rewrite the driver to use some commun video4linux API for snapshot
+	  and mjpeg capture. Unfortunately, video4linux1 does not permit it,
+	  the BUZ API seems to be targeted to TV cards only. The video4linux 2
+	  API may be an option, if it goes into the kernel (maybe 2.5 
+	  material ?).
diff -u --recursive --new-file v2.4.6/linux/Documentation/video4linux/w9966.txt linux/Documentation/video4linux/w9966.txt
--- v2.4.6/linux/Documentation/video4linux/w9966.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/w9966.txt	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,37 @@
+
+W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se)
+
+Ok, after a lot of work in softice, wdasm, reading pdf-files
+and trial-and-error work I've finally got everything to work.
+Since I needed some vision for a robotics project I borrowed
+this camera from a friend and started hacking. Anyway I've
+converted my original code from the AVR 8bit RISC C/asm
+into a working linux driver. I would really appreciate _any_
+kind of feedback regarding this driver.
+
+To get it working quickly configure your kernel
+to support parport, ieee1284, video4linux, experimental drivers
+and w9966
+
+If w9966 is statically linked it will perform aggressive probing
+for the camera. If built as a module you'll have more configuration options.
+
+Options:
+modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
+ 
+voila!
+
+you can also type 'modinfo -p w9966.o' for option usage
+(or checkout w9966.c)
+
+I've only tested it with custom built testprograms
+(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam.
+(you'll need to tweak the code to qcam a bit to make it work,
+dimensions and such)
+
+The slow framerate is due to missing DMA ECP read support in the 
+parport drivers. I might add working EPP support later.
+
+Good luck!
+
+    /Jakob
diff -u --recursive --new-file v2.4.6/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.6/linux/MAINTAINERS	Tue Jul  3 17:08:18 2001
+++ linux/MAINTAINERS	Fri Jul  6 17:06:52 2001
@@ -106,6 +106,12 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+ACENIC DRIVER
+P:	Jes Sorensen
+M:	jes@trained-monkey.org
+L:	linux-acenic@sunsite.dk
+S:	Maintained
+
 ACI MIXER DRIVER
 P:	Robert Siemer
 M:	Robert.Siemer@gmx.de
@@ -566,8 +572,8 @@
 
 HIPPI
 P:	Jes Sorensen
-M:	jes@linuxcare.com
-L:	linux-hippi@sunsite.auc.dk
+M:	jes@trained-monkey.org
+L:	linux-hippi@sunsite.dk
 S:	Maintained
 
 HP100:	Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
@@ -812,7 +818,7 @@
 
 M68K
 P:	Jes Sorensen
-M:	jes@linuxcare.com
+M:	jes@trained-monkey.org
 W:	http://www.clark.net/pub/lawrencc/linux/index.html
 L:	linux-m68k@lists.linux-m68k.org
 S:	Maintained
diff -u --recursive --new-file v2.4.6/linux/Makefile linux/Makefile
--- v2.4.6/linux/Makefile	Tue Jul  3 17:08:18 2001
+++ linux/Makefile	Thu Jul  5 11:54:28 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 6
-EXTRAVERSION =
+SUBLEVEL = 7
+EXTRAVERSION =-pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.4.6/linux/arch/alpha/kernel/time.c	Sun Nov 12 19:27:11 2000
+++ linux/arch/alpha/kernel/time.c	Wed Jul  4 11:50:46 2001
@@ -169,6 +169,77 @@
 	init_rtc_irq();
 }
 
+/*
+ * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
+ * arch/i386/time.c.
+ */
+
+#define CALIBRATE_LATCH	(52 * LATCH)
+#define CALIBRATE_TIME	(52 * 1000020 / HZ)
+
+static unsigned long __init
+calibrate_cc_with_pic(void)
+{
+	int cc;
+	unsigned long count = 0;
+
+	/* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	/*
+	 * Now let's take care of CTC channel 2
+	 *
+	 * Set the Gate high, program CTC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 */
+	outb(0xb0, 0x43);		/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
+	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
+
+	cc = rpcc();
+	do {
+		count++;
+	} while ((inb(0x61) & 0x20) == 0);
+	cc = rpcc() - cc;
+
+	/* Error: ECTCNEVERSET */
+	if (count <= 1)
+		goto bad_ctc;
+
+	/* Error: ECPUTOOFAST */
+	if (count >> 32)
+		goto bad_ctc;
+
+	/* Error: ECPUTOOSLOW */
+	if (cc <= CALIBRATE_TIME)
+		goto bad_ctc;
+
+	return ((long)cc * 1000000) / CALIBRATE_TIME;
+
+	/*
+	 * The CTC wasn't reliable: we got a hit on the very first read,
+	 * or the CPU was so fast/slow that the quotient wouldn't fit in
+	 * 32 bits..
+	 */
+ bad_ctc:
+	return 0;
+}
+
+/* The Linux interpretation of the CMOS clock register contents:
+   When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+   RTC registers show the second which has precisely just started.
+   Let's hope other operating systems interpret the RTC the same way.  */
+
+static unsigned long __init
+rpcc_after_update_in_progress(void)
+{
+	do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
+	do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+
+	return rpcc();
+}
+
 void __init
 time_init(void)
 {
@@ -176,24 +247,15 @@
 	unsigned long cycle_freq, one_percent;
 	long diff;
 
-	/*
-	 * The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
-	do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+	/* Calibrate CPU clock -- attempt #1.  */
+	if (!est_cycle_freq)
+		est_cycle_freq = calibrate_cc_with_pic();
 
-	/* Read cycle counter exactly on falling edge of update flag */
-	cc1 = rpcc();
+	cc1 = rpcc_after_update_in_progress();
 
+	/* Calibrate CPU clock -- attempt #2.  */
 	if (!est_cycle_freq) {
-		/* Sometimes the hwrpb->cycle_freq value is bogus. 
-		   Go another round to check up on it and see.  */
-		do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
-		do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-		cc2 = rpcc();
+		cc2 = rpcc_after_update_in_progress();
 		est_cycle_freq = cc2 - cc1;
 		cc1 = cc2;
 	}
diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.4.6/linux/arch/alpha/kernel/traps.c	Thu May 24 15:24:37 2001
+++ linux/arch/alpha/kernel/traps.c	Wed Jul  4 11:50:38 2001
@@ -61,202 +61,6 @@
 			   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
 			   "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};
 
-static char * inst_name[] = {"call_pal", "", "", "", "", "", "", "",
-	"lda", "ldah", "ldbu", "ldq_u", "ldwu", "stw", "stb", "stq_u",
-	"ALU", "ALU", "ALU", "ALU", "SQRT", "FVAX", "FIEEE", "FLOAT",
-	"MISC", "PAL19", "JMP", "PAL1B", "GRAPH", "PAL1D", "PAL1E", "PAL1F",
-	"ldf", "ldg", "lds", "ldt", "stf", "stg", "sts", "stt",
-	"ldl", "ldq", "ldl_l", "ldq_l", "stl", "stq", "stl_c", "stq_c",
-	"br", "fbeq", "fblt", "fble", "bsr", "fbne", "fbge", "fbgt"
-	"blbc", "beq", "blt", "ble", "blbs", "bne", "bge", "bgt"
-};
-
-static char * jump_name[] = {"jmp", "jsr", "ret", "jsr_coroutine"};
-
-typedef struct {int func; char * text;} alist;
-
-static alist inta_name[] = {{0, "addl"}, {2, "s4addl"}, {9, "subl"},
-	{0xb, "s4subl"}, {0xf, "cmpbge"}, {0x12, "s8addl"}, {0x1b, "s8subl"},
-	{0x1d, "cmpult"}, {0x20, "addq"}, {0x22, "s4addq"}, {0x29, "subq"},
-	{0x2b, "s4subq"}, {0x2d, "cmpeq"}, {0x32, "s8addq"}, {0x3b, "s8subq"},
-	{0x3d, "cmpule"}, {0x40, "addl/v"}, {0x49, "subl/v"}, {0x4d, "cmplt"},
-	{0x60, "addq/v"}, {0x69, "subq/v"}, {0x6d, "cmple"}, {-1, 0}};
-
-static alist intl_name[] = {{0, "and"}, {8, "andnot"}, {0x14, "cmovlbs"},
-	{0x16, "cmovlbc"}, {0x20, "or"}, {0x24, "cmoveq"}, {0x26, "cmovne"},
-	{0x28, "ornot"}, {0x40, "xor"}, {0x44, "cmovlt"}, {0x46, "cmovge"},
-	{0x48, "eqv"}, {0x61, "amask"}, {0x64, "cmovle"}, {0x66, "cmovgt"},
-	{0x6c, "implver"}, {-1, 0}};
-
-static alist ints_name[] = {{2, "mskbl"}, {6, "extbl"}, {0xb, "insbl"},
-	{0x12, "mskwl"}, {0x16, "extwl"}, {0x1b, "inswl"}, {0x22, "mskll"},
-	{0x26, "extll"}, {0x2b, "insll"}, {0x30, "zap"}, {0x31, "zapnot"},
-	{0x32, "mskql"}, {0x34, "srl"}, {0x36, "extql"}, {0x39, "sll"},
-	{0x3b, "insql"}, {0x3c, "sra"}, {0x52, "mskwh"}, {0x57, "inswh"},
-	{0x5a, "extwh"}, {0x62, "msklh"}, {0x67, "inslh"}, {0x6a, "extlh"},
-	{0x72, "mskqh"}, {0x77, "insqh"}, {0x7a, "extqh"}, {-1, 0}};
-
-static alist intm_name[] = {{0, "mull"}, {0x20, "mulq"}, {0x30, "umulh"},
-	{0x40, "mull/v"}, {0x60, "mulq/v"}, {-1, 0}};
-
-static alist * int_name[] = {inta_name, intl_name, ints_name, intm_name};
-
-static char *
-assoc(int fcode, alist * a)
-{
-	while ((fcode != a->func) && (a->func != -1))
-		++a;
-	return a->text;
-}
-
-static char *
-iname(unsigned int instr)
-{
-	int opcode = instr >> 26;
-	char * name = inst_name[opcode];
-
-	switch (opcode) {
-		default:
-			break;
-
-		case 0x10:
-		case 0x11:
-		case 0x12:
-		case 0x13: {
-			char * specific_name
-			  = assoc((instr >> 5) & 0x3f, int_name[opcode - 0x10]);
-			if (specific_name)
-				name = specific_name;
-			break;
-		}
-
-		case 0x1a:
-			name = jump_name[(instr >> 14) & 3];
-			break;
-	}
-	
-	return name;
-}
-
-static enum {NOT_INST, PAL, BRANCH, MEMORY, JUMP, OPERATE, FOPERATE, MISC}
-iformat(int opcode)
-{
-	if (opcode >= 0x30)
-		return BRANCH;
-	if (opcode >= 0x20)
-		return MEMORY;
-	if (opcode == 0)
-		return PAL;
-	if (opcode < 8)
-		return NOT_INST;
-	if (opcode < 0x10)
-		return MEMORY;
-	if (opcode < 0x14)
-		return OPERATE;
-	if (opcode < 0x18)
-		return FOPERATE;
-	switch (opcode) {
-		case 0x18:
-			return MISC;
-		case 0x1A:
-			return JUMP;
-		case 0x1C:
-			return OPERATE;
-		default:
-			return NOT_INST;
-	}
-}
-
-/*
- * The purpose here is to provide useful clues about a kernel crash, so
- * less likely instructions, e.g. floating point, aren't fully decoded.
- */
-static void
-disassemble(unsigned int instr)
-{
-	int optype = instr >> 26;
-	char buf[40], *s = buf;
-
-	s += sprintf(buf, "%08x  %s ", instr, iname(instr));
-	switch (iformat(optype)) {
-		default:
-		case NOT_INST:
-		case MISC:
-			break;
-
-		case PAL:
-			s += sprintf(s, "%d", instr);
-			break;
-
-		case BRANCH: {
-			int reg = (instr >> 21) & 0x1f;
-			int offset = instr & 0x1fffff;
-
-			if (offset >= 0x100000)
-				offset -= 0x200000;
-			if (((optype & 3) == 0) || (optype >= 0x38)) {
-				if ((optype != 0x30) || (reg != 0x1f))
-					s += sprintf(s, "%s,", ireg_name[reg]);
-			} else
-				s += sprintf(s, "f%d,", reg);
-			s += sprintf(s, ".%+d", (offset + 1) << 2);
-			break;
-		}
-
-		case MEMORY: {
-			int addr_reg = (instr >> 16) & 0x1f;
-			int value_reg = (instr >> 21) & 0x1f;
-			int offset = instr & 0xffff;
-
-			if (offset >= 0x8000)
-				offset -= 0x10000;
-			if ((optype >= 0x20) && (optype < 0x28))
-				s += sprintf(s, "f%d", value_reg);
-			else
-				s += sprintf(s, "%s", ireg_name[value_reg]);
-
-			s += sprintf(s, ",%d(%s)", offset, ireg_name[addr_reg]);
-			break;
-		}
-
-		case JUMP: {
-			int target_reg = (instr >> 16) & 0x1f;
-			int return_reg = (instr >> 21) & 0x1f;
-
-			s += sprintf(s, "%s,", ireg_name[return_reg]);
-			s += sprintf(s, "(%s)", ireg_name[target_reg]);
-			break;
-		}
-
-		case OPERATE: {
-			int areg = (instr >> 21) & 0x1f;
-			int breg = (instr >> 16) & 0x1f;
-			int creg = instr & 0x1f;
-			int litflag = instr & (1<<12);
-			int lit = (instr >> 13) & 0xff;
-
-			s += sprintf(s, "%s,", ireg_name[areg]);
-			if (litflag)
-				s += sprintf(s, "%d", lit);
-			else
-				s += sprintf(s, "%s", ireg_name[breg]);
-			s += sprintf(s, ",%s", ireg_name[creg]);
-			break;
-		}
-
-		case FOPERATE: {
-			int areg = (instr >> 21) & 0x1f;
-			int breg = (instr >> 16) & 0x1f;
-			int creg = instr & 0x1f;
-
-			s += sprintf(s, "f%d,f%d,f%d", areg, breg, creg);
-			break;
-		}
-	}
-	buf[s-buf] = 0;
-	printk("%s\n", buf);
-}
-
 static void
 dik_show_code(unsigned int *pc)
 {
@@ -267,8 +71,7 @@
 		unsigned int insn;
 		if (__get_user(insn, pc+i))
 			break;
-		printk("%c", i ? ' ' : '*');
-		disassemble(insn);
+		printk("%c%08x%c", i ? ' ' : '<', insn, i ? ' ' : '>');
 	}
 	printk("\n");
 }
@@ -286,17 +89,11 @@
 			continue;
 		if (tmp >= (unsigned long) &_etext)
 			continue;
-		/*
-		 * Assume that only the low 24-bits of a kernel text address
-		 * is interesting.
-		 */
-		printk("%6x%c", (int)tmp & 0xffffff, (++i % 11) ? ' ' : '\n');
-#if 0
+		printk("%lx%c", tmp, ' ');
 		if (i > 40) {
 			printk(" ...");
 			break;
 		}
-#endif
 	}
 	printk("\n");
 }
@@ -337,8 +134,8 @@
 #endif
 	printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
 	dik_show_regs(regs, r9_15);
-	dik_show_code((unsigned int *)regs->pc);
 	dik_show_trace((unsigned long *)(regs+1));
+	dik_show_code((unsigned int *)regs->pc);
 
 	if (current->thread.flags & (1UL << 63)) {
 		printk("die_if_kernel recursion detected.\n");
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.4.6/linux/arch/arm/kernel/bios32.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/bios32.c	Wed Jul  4 15:43:05 2001
@@ -8,6 +8,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 
 #include <asm/page.h> /* for BUG() */
@@ -18,6 +19,20 @@
 static int debug_pci;
 int have_isa_bridge;
 
+struct pci_sys_data {
+	/*
+	 * The hardware we are attached to
+	 */
+	struct hw_pci	*hw;
+
+	unsigned long	mem_offset;
+
+	/*
+	 * These are the resources for the root bus.
+	 */
+	struct resource *resource[3];
+};
+
 void pcibios_report_status(u_int status_mask, int warn)
 {
 	struct pci_dev *dev;
@@ -118,19 +133,22 @@
 }
 
 /*
- * Prevent the PCI layer from seeing the resources
- * allocated to this device.  These resources are
- * of no consequence to the PCI layer (they are
- * handled elsewhere).
+ * Prevent the PCI layer from seeing the resources allocated to this device
+ * if it is the host bridge by marking it as such.  These resources are of
+ * no consequence to the PCI layer (they are handled elsewhere).
  */
-static void __init pci_fixup_disable(struct pci_dev *dev)
+static void __init pci_fixup_dec21285(struct pci_dev *dev)
 {
 	int i;
 
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		dev->resource[i].start = 0;
-		dev->resource[i].end   = 0;
-		dev->resource[i].flags = 0;
+	if (dev->devfn == 0) {
+		dev->class &= 0xff;
+		dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			dev->resource[i].start = 0;
+			dev->resource[i].end   = 0;
+			dev->resource[i].flags = 0;
+		}
 	}
 }
 
@@ -167,7 +185,7 @@
 	{
 		PCI_FIXUP_HEADER,
 		PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_21285,
-		pci_fixup_disable
+		pci_fixup_dec21285
 	}, {
 		PCI_FIXUP_HEADER,
 		PCI_VENDOR_ID_WINBOND,	PCI_DEVICE_ID_WINBOND_83C553,
@@ -187,27 +205,11 @@
 	}, { 0 }
 };
 
-/*
- * Allocate resources for all PCI devices that have been enabled.
- * We need to do that before we try to fix up anything.
- */
-static void __init pcibios_claim_resources(void)
-{
-	struct pci_dev *dev;
-	int idx;
-
-	pci_for_each_dev(dev) {
-		for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
-			if (dev->resource[idx].flags &&
-			    dev->resource[idx].start)
-				pci_claim_resource(dev, idx);
-	}
-}
-
 void __init
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			struct resource *res, int resource)
 {
+	struct pci_sys_data *sys = dev->sysdata;
 	u32 val, check;
 	int reg;
 
@@ -216,12 +218,9 @@
 			res->flags & IORESOURCE_IO ? "IO" : "MEM",
 			res->start, dev->name);
 
-	val = res->start | (res->flags & PCI_REGION_FLAG_MASK);
 	if (resource < 6) {
 		reg = PCI_BASE_ADDRESS_0 + 4*resource;
 	} else if (resource == PCI_ROM_RESOURCE) {
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
-		val |= PCI_ROM_ADDRESS_ENABLE;
 		reg = dev->rom_base_reg;
 	} else {
 		/* Somebody might have asked allocation of a
@@ -229,6 +228,12 @@
 		 */
 		return;
 	}
+
+	val = res->start;
+	if (res->flags & IORESOURCE_MEM)
+		val -= sys->mem_offset;
+	val |= res->flags & PCI_REGION_FLAG_MASK;
+
 	pci_write_config_dword(dev, reg, val);
 	pci_read_config_dword(dev, reg, &check);
 	if ((val ^ check) & ((val & PCI_BASE_ADDRESS_SPACE_IO) ?
@@ -246,77 +251,93 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-/**
- * pcibios_fixup_bus - Called after each bus is probed, but before its children
- * are examined.
+/*
+ * If the bus contains any of these devices, then we must not turn on
+ * parity checking of any kind.  Currently this is CyberPro 20x0 only.
  */
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+static inline int pdev_bad_for_parity(struct pci_dev *dev)
+{
+	return (dev->vendor == PCI_VENDOR_ID_INTERG &&
+		(dev->device == PCI_DEVICE_ID_INTERG_2000 ||
+		 dev->device == PCI_DEVICE_ID_INTERG_2010));
+}
+
+/*
+ * Adjust the device resources from bus-centric to Linux-centric.
+ */
+static void __init
+pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (dev->resource[i].start == 0)
+			continue;
+		if (dev->resource[i].flags & IORESOURCE_MEM) {
+			dev->resource[i].start += root->mem_offset;
+			dev->resource[i].end   += root->mem_offset;
+		}
+	}
+}
+
+static void __init
+pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root)
 {
-	struct list_head *walk = &bus->devices;
-	struct arm_pci_sysdata *sysdata =
-			(struct arm_pci_sysdata *)bus->sysdata;
-	struct arm_bus_sysdata *busdata;
-
-	if (bus->number >= MAX_NR_BUS)
-		BUG();
-
-	if (bus->self) {
-		struct pci_dev *dev = bus->self;
-		int i;
+	struct pci_dev *dev = bus->self;
+	int i;
 
+	if (dev) {
 		for (i = 0; i < 3; i++) {
-			bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES + i];
-			bus->resource[i]->name = bus->name;
+			bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+			bus->resource[i]->name  = bus->name;
 		}
-		bus->resource[0]->start = ioport_resource.start;
-		bus->resource[0]->end   = ioport_resource.end;
 		bus->resource[0]->flags |= pci_bridge_check_io(dev);
-		bus->resource[1]->start = iomem_resource.start;
-		bus->resource[1]->end   = iomem_resource.end;
 		bus->resource[1]->flags |= IORESOURCE_MEM;
 
-		/* Turn off downsteam prefetchable memory address range */
-		bus->resource[2]->start = 1024*1024;
-		bus->resource[2]->end   = bus->resource[2]->start - 1;
+		if (root->resource[2])
+			bus->resource[2]->flags = root->resource[2]->flags;
+		else {
+			/* no prefetchable memory region - disable it */
+			bus->resource[2]->start = 1024*1024;
+			bus->resource[2]->end   = bus->resource[2]->start - 1;
+		}
+	} else {
+		/*
+		 * Assign root bus resources.
+		 */
+		for (i = 0; i < 3; i++)
+			bus->resource[i] = root->resource[i];
 	}
+}
 
-	busdata = sysdata->bus + bus->number;
-	busdata->max_lat = 255;
+/*
+ * pcibios_fixup_bus - Called after each bus is probed,
+ * but before its children are examined.
+ */
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_sys_data *root = bus->sysdata;
+	struct list_head *walk;
+	u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
+	u16 all_status = -1;
+
+	pbus_assign_bus_resources(bus, root);
 
 	/*
 	 * Walk the devices on this bus, working out what we can
 	 * and can't support.
 	 */
-	for (walk = walk->next; walk != &bus->devices; walk = walk->next) {
+	for (walk = bus->devices.next; walk != &bus->devices; walk = walk->next) {
 		struct pci_dev *dev = pci_dev_b(walk);
 		u16 status;
-		u8 max_lat, min_gnt;
-
-		pci_read_config_word(dev, PCI_STATUS, &status);
 
-		/*
-		 * If this device does not support fast back to back
-		 * transfers, the bus as a whole cannot support them.
-		 */
-		if (!(status & PCI_STATUS_FAST_BACK))
-			busdata->features &= ~PCI_COMMAND_FAST_BACK;
+		pdev_fixup_device_resources(root, dev);
 
-		/*
-		 * If we encounter a CyberPro 2000, then we disable
-		 * SERR and PERR reporting - this chip doesn't drive the
-		 * parity line correctly.
-		 */
-		if (dev->vendor == PCI_VENDOR_ID_INTERG &&
-		    (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
-		     dev->device == PCI_DEVICE_ID_INTERG_2010))
-			busdata->features &= ~(PCI_COMMAND_SERR |
-					       PCI_COMMAND_PARITY);
+		pci_read_config_word(dev, PCI_STATUS, &status);
+		all_status &= status;
 
-		/*
-		 * Calculate the maximum devsel latency.
-		 */
-		if (busdata->maxdevsel < (status & PCI_STATUS_DEVSEL_MASK))
-			busdata->maxdevsel = (status & PCI_STATUS_DEVSEL_MASK);
+		if (pdev_bad_for_parity(dev))
+			features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
 
 		/*
 		 * If this device is an ISA bridge, set the have_isa_bridge
@@ -326,63 +347,48 @@
 		if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA ||
 		    dev->class >> 8 == PCI_CLASS_BRIDGE_EISA)
 			have_isa_bridge = !0;
-
-		/*
-		 * Calculate the maximum latency on this bus.  Note
-		 * that we ignore any device which reports its max
-		 * latency is the same as its use.
-		 */
-		pci_read_config_byte(dev, PCI_MAX_LAT, &max_lat);
-		pci_read_config_byte(dev, PCI_MIN_GNT, &min_gnt);
-		if (max_lat && max_lat != min_gnt && max_lat < busdata->max_lat)
-			busdata->max_lat = max_lat;
 	}
 
 	/*
+	 * If any device on this bus does not support fast back to back
+	 * transfers, then the bus as a whole is not able to support them.
+	 * Having fast back to back transfers on saves us one PCI cycle
+	 * per transaction.
+	 */
+	if (all_status & PCI_STATUS_FAST_BACK)
+		features |= PCI_COMMAND_FAST_BACK;
+
+	/*
 	 * Now walk the devices again, this time setting them up.
 	 */
-	walk = &bus->devices;
-	for (walk = walk->next; walk != &bus->devices; walk = walk->next) {
+	for (walk = bus->devices.next; walk != &bus->devices; walk = walk->next) {
 		struct pci_dev *dev = pci_dev_b(walk);
 		u16 cmd;
-		u8 min_gnt, latency;
-
-		/*
-		 * Calculate this masters latency timer value.
-		 * This is rather primitive - it does not take
-		 * account of the number of masters in a system
-		 * wanting to use the bus.
-		 */
-		pci_read_config_byte(dev, PCI_MIN_GNT, &min_gnt);
-		if (min_gnt) {
-			if (min_gnt > busdata->max_lat)
-				min_gnt = busdata->max_lat;
-
-			latency = (int)min_gnt * 25 / 3;
-		} else
-			latency = 32; /* 1us */
-
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
 
-		/*
-		 * Set the cache line size to 32 bytes.
-		 * Also, set system error enable, parity error enable.
-		 * Disable ROM.
-		 */
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
 		pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-		cmd |= busdata->features;
-
+		cmd |= features;
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
-		pci_read_config_word(dev, PCI_COMMAND, &cmd);
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
 	}
+
+	/*
+	 * Report what we did for this bus
+	 */
+	printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n",
+		bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
 }
 
+/*
+ * Convert from Linux-centric to bus-centric addresses for bridge devices.
+ */
 void __init
 pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
 {
+	struct pci_sys_data *root = bus->sysdata;
+
+	ranges->mem_start -= root->mem_offset;
+	ranges->mem_end -= root->mem_offset;
+	ranges->prefetch_start -= root->mem_offset;
+	ranges->prefetch_end -= root->mem_offset;
 }
 
 u8 __init no_swizzle(struct pci_dev *dev, u8 *pin)
@@ -400,81 +406,90 @@
 
 void __init pcibios_init(void)
 {
-	struct hw_pci *hw_pci = NULL;
-	struct arm_pci_sysdata sysdata;
-	int i;
+	struct pci_sys_data *root;
+	struct hw_pci *hw = NULL;
 
 	do {
 #ifdef CONFIG_ARCH_EBSA285
 		if (machine_is_ebsa285()) {
-			hw_pci = &ebsa285_pci;
+			hw = &ebsa285_pci;
 			break;
 		}
 #endif
 #ifdef CONFIG_ARCH_SHARK
 		if (machine_is_shark()) {
-			hw_pci = &shark_pci;
+			hw = &shark_pci;
 			break;
 		}
 #endif
 #ifdef CONFIG_ARCH_CATS
 		if (machine_is_cats()) {
-			hw_pci = &cats_pci;
+			hw = &cats_pci;
 			break;
 		}
 #endif
 #ifdef CONFIG_ARCH_NETWINDER
 		if (machine_is_netwinder()) {
-			hw_pci = &netwinder_pci;
+			hw = &netwinder_pci;
 			break;
 		}
 #endif
 #ifdef CONFIG_ARCH_PERSONAL_SERVER
 		if (machine_is_personal_server()) {
-			hw_pci = &personal_server_pci;
+			hw = &personal_server_pci;
 			break;
 		}
 #endif
 #ifdef CONFIG_ARCH_FTVPCI
 		if (machine_is_ftvpci()) {
-			hw_pci = &ftv_pci;
+			hw = &ftv_pci;
 			break;
 		}
 #endif
 #ifdef CONFIG_ARCH_INTEGRATOR
 		if (machine_is_integrator()) {
-			hw_pci = &integrator_pci;
+			hw = &integrator_pci;
 			break;
 		}
 #endif
 	} while (0);
 
-	if (hw_pci == NULL)
+	if (hw == NULL)
 		return;
 
-	for (i = 0; i < MAX_NR_BUS; i++) {
-		sysdata.bus[i].features  = PCI_COMMAND_FAST_BACK |
-					   PCI_COMMAND_SERR |
-					   PCI_COMMAND_PARITY;
-		sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST;
+	root = kmalloc(sizeof(*root), GFP_KERNEL);
+	if (!root)
+		panic("PCI: unable to allocate root data!");
+
+	root->hw = hw;
+	root->mem_offset = hw->mem_offset;
+
+	memset(root->resource, 0, sizeof(root->resource));
+
+	/*
+	 * Setup the resources for this bus.
+	 *   resource[0] - IO ports
+	 *   resource[1] - non-prefetchable memory
+	 *   resource[2] - prefetchable memory
+	 */
+	if (root->hw->setup_resources)
+		root->hw->setup_resources(root->resource);
+	else {
+		root->resource[0] = &ioport_resource;
+		root->resource[1] = &iomem_resource;
+		root->resource[2] = NULL;
 	}
 
 	/*
 	 * Set up the host bridge, and scan the bus.
 	 */
-	hw_pci->init(&sysdata);
-
-	/*
-	 * Claim the currently allocated resources.  This ensures
-	 * that we will not allocate an already inuse region.
-	 */
-	pcibios_claim_resources();
+	root->hw->init(root);
 
 	/*
 	 * Assign any unassigned resources.
 	 */
 	pci_assign_unassigned_resources();
-	pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq);
+	pci_fixup_irqs(root->hw->swizzle, root->hw->map_irq);
 }
 
 char * __init pcibios_setup(char *str)
@@ -499,7 +514,7 @@
  * is reserved for motherboard devices that decode all 16
  * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
  * but we want to try to avoid allocating at 0x2900-0x2bff
- * which might have be mirrored at 0x0100-0x03ff..
+ * which might be mirrored at 0x0100-0x03ff..
  */
 void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
 {
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c
--- v2.4.6/linux/arch/arm/kernel/dec21285.c	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/kernel/dec21285.c	Wed Jul  4 15:43:05 2001
@@ -13,6 +13,7 @@
 #include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 
@@ -24,6 +25,11 @@
 
 #define MAX_SLOTS		21
 
+#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \
+			PCI_STATUS_REC_MASTER_ABORT | \
+			PCI_STATUS_REC_TARGET_ABORT | \
+			PCI_STATUS_PARITY) << 16)
+
 extern int setup_arm_irq(int, struct irqaction *);
 extern void pcibios_report_status(u_int status_mask, int warn);
 extern void register_isa_ports(unsigned int, unsigned int, unsigned int);
@@ -255,12 +261,33 @@
 	add_timer(timer);
 }
 
-void __init dc21285_init(struct arm_pci_sysdata *sysdata)
+void __init dc21285_setup_resources(struct resource **resource)
+{
+	struct resource *busmem, *busmempf;
+
+	busmem = kmalloc(sizeof(*busmem), GFP_KERNEL);
+	busmempf = kmalloc(sizeof(*busmempf), GFP_KERNEL);
+	memset(busmem, 0, sizeof(*busmem));
+	memset(busmempf, 0, sizeof(*busmempf));
+
+	busmem->flags = IORESOURCE_MEM;
+	busmem->name  = "Footbridge non-prefetch";
+	busmempf->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+	busmempf->name  = "Footbridge prefetch";
+
+	allocate_resource(&iomem_resource, busmempf, 0x20000000,
+			  0x80000000, 0xffffffff, 0x20000000, NULL, NULL);
+	allocate_resource(&iomem_resource, busmem, 0x40000000,
+			  0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
+
+	resource[0] = &ioport_resource;
+	resource[1] = busmem;
+	resource[2] = busmempf;
+}
+
+void __init dc21285_init(void *sysdata)
 {
-	unsigned long cntl;
 	unsigned int mem_size, mem_mask;
-	unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-				PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
 	int cfn_mode;
 
 	mem_size = (unsigned int)high_memory - PAGE_OFFSET;
@@ -286,26 +313,17 @@
 		"central function" : "addin");
 
 	if (cfn_mode) {
-		static struct resource csrmem, csrio, busmem, busmempf;
-		struct pci_bus *bus;
+		static struct resource csrmem, csrio;
 
-		csrio.flags = IORESOURCE_IO;
-		csrio.name  = "Footbridge";
+		csrio.flags  = IORESOURCE_IO;
+		csrio.name   = "Footbridge";
 		csrmem.flags = IORESOURCE_MEM;
 		csrmem.name  = "Footbridge";
-		busmem.flags = IORESOURCE_MEM;
-		busmem.name  = "Footbridge non-prefetch";
-		busmempf.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-		busmempf.name  = "Footbridge prefetch";
 
 		allocate_resource(&ioport_resource, &csrio, 128,
 				  0xff00, 0xffff, 128, NULL, NULL);
 		allocate_resource(&iomem_resource, &csrmem, 128,
 				  0xf4000000, 0xf8000000, 128, NULL, NULL);
-		allocate_resource(&iomem_resource, &busmempf, 0x20000000,
-				  0x00000000, 0x80000000, 0x20000000, NULL, NULL);
-		allocate_resource(&iomem_resource, &busmem, 0x40000000,
-				  0x00000000, 0x80000000, 0x40000000, NULL, NULL);
 
 		/*
 		 * Map our SDRAM at a known address in PCI space, just in case
@@ -313,37 +331,23 @@
 		 * necessary, since some VGA cards forcefully use PCI addresses
 		 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
 		 */
-		*CSR_PCICACHELINESIZE = 0x00002008;
 		*CSR_PCICSRBASE       = csrmem.start;
 		*CSR_PCICSRIOBASE     = csrio.start;
 		*CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
 		*CSR_PCIROMBASE       = 0;
-		*CSR_PCICMD           = pci_cmd |
-				(1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
-
-		bus = pci_scan_bus(0, &dc21285_ops, sysdata);
-		/*
-		 * bus->resource[0] is the IO resource for this bus
-		 * bus->resource[1] is the mem resource for this bus
-		 * bus->resource[2] is the prefetch mem resource for this bus
-		 */
-		bus->resource[1] = &busmem;
-		bus->resource[2] = &busmempf;
-
-		pci_cmd |= sysdata->bus[0].features;
+		*CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+			      PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS;
 
-		printk("PCI: Fast back to back transfers %sabled\n",
-		       (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ?
-			"en" : "dis");
+		pci_scan_bus(0, &dc21285_ops, sysdata);
 
 		/*
 		 * Clear any existing errors - we aren't
 		 * interested in historical data...
 		 */
-		cntl		= *CSR_SA110_CNTL & 0xffffde07;
-		*CSR_SA110_CNTL	= cntl | SA110_CNTL_RXSERR;
-		*CSR_PCICMD	= pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24;
-	} else {
+		*CSR_SA110_CNTL	= (*CSR_SA110_CNTL & 0xffffde07) |
+				  SA110_CNTL_RXSERR;
+		*CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
+	} else if (footbridge_cfn_mode() != 0) {
 		/*
 		 * If we are not compiled to accept "add-in" mode, then
 		 * we are using a constant virt_to_bus translation which
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c
--- v2.4.6/linux/arch/arm/kernel/dma-arc.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/kernel/dma-arc.c	Wed Jul  4 14:56:44 2001
@@ -155,7 +155,7 @@
 	}
 	memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
 	regs.ARM_r9 = dma->buf.length;
-	regs.ARM_r10 = dma->buf.address;
+	regs.ARM_r10 = (unsigned long)dma->buf.address;
 	regs.ARM_fp = FLOPPYDMA_BASE;
 	set_fiq_regs(&regs);
 	enable_fiq(dma->dma_irq);
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.4.6/linux/arch/arm/kernel/head-armv.S	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/head-armv.S	Wed Jul  4 14:56:44 2001
@@ -79,7 +79,7 @@
  *     ideal, but in this case, it should ONLY set r0 and r1 to the
  *     appropriate value.
  */
-#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_INTEGRATOR)
+#if defined(CONFIG_ARCH_NETWINDER)
 /*
  * Compatability cruft for old NetWinder NeTTroms.  This
  * code is currently scheduled for destruction in 2.5.xx
@@ -124,8 +124,6 @@
  * FIXME - No bootloader, so manually set 'r1' with our architecture number.
  */
 		mov	r1, #MACH_TYPE_L7200
-#elif defined(CONFIG_ARCH_INTEGRATOR)
-		mov	r1, #MACH_TYPE_INTEGRATOR
 #endif
 
 		mov	r0, #F_BIT | I_BIT | MODE_SVC	@ make sure svc mode
@@ -236,14 +234,16 @@
 		 * nearest megabyte boundary.
 		 */
 		add	r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
+		bic	r2, r3, #0x00f00000
+		str	r2, [r0]			@ PAGE_OFFSET + 0MB
 		add	r0, r0, #(TEXTADDR & 0x00f00000) >> 18
-		str	r3, [r0], #4			@ PAGE_OFFSET + 0MB
+		str	r3, [r0], #4			@ KERNEL + 0MB
 		add	r3, r3, #1 << 20
-		str	r3, [r0], #4			@ PAGE_OFFSET + 1MB
+		str	r3, [r0], #4			@ KERNEL + 1MB
 		add	r3, r3, #1 << 20
-		str	r3, [r0], #4			@ PAGE_OFFSET + 2MB
+		str	r3, [r0], #4			@ KERNEL + 2MB
 		add	r3, r3, #1 << 20
-		str	r3, [r0], #4			@ PAGE_OFFSET + 3MB
+		str	r3, [r0], #4			@ KERNEL + 3MB
 
 		/*
 		 * Ensure that the first section of RAM is present.
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.4.6/linux/arch/arm/kernel/irq.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/irq.c	Wed Jul  4 14:56:44 2001
@@ -216,7 +216,7 @@
 
 	irq_exit(cpu, irq);
 
-	if (softirq_active(cpu) & softirq_mask(cpu))
+	if (softirq_pending(cpu))
 		do_softirq();
 	return;
 
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c
--- v2.4.6/linux/arch/arm/kernel/oldlatches.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/oldlatches.c	Wed Jul  4 14:56:44 2001
@@ -50,13 +50,14 @@
 		BUG();
 }
 
-static void __init oldlatch_init(void)
+static int __init oldlatch_init(void)
 {
 	if (machine_is_archimedes()) {
 		oldlatch_aupdate(0xff, 0xff);
 		/* Thats no FDC reset...*/
 		oldlatch_bupdate(0xff, LATCHB_FDCRESET);
 	}
+	return 0;
 }
 
 __initcall(oldlatch_init);
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/plx90x0.c linux/arch/arm/kernel/plx90x0.c
--- v2.4.6/linux/arch/arm/kernel/plx90x0.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/kernel/plx90x0.c	Wed Jul  4 15:43:05 2001
@@ -129,8 +129,6 @@
 	static const unsigned long int base = PLX_BASE;
 	char *what;
 	unsigned long bar = (unsigned long)virt_to_bus((void *)PAGE_OFFSET);
-	unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-				PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
 
 	/* Have a sniff around and see which PLX device is present. */
 	unsigned long id = __raw_readl(base + 0xf0);
@@ -189,10 +187,4 @@
 		    "system error", NULL);
 
 	pci_scan_bus(0, &plx90x0_ops, sysdata);
-
-	pci_cmd |= sysdata->bus[0].features;
-
-	printk("PCI: Fast back to back transfers %sabled\n",
-	       (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ?
-	       "en" : "dis");
 }
diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.4.6/linux/arch/arm/kernel/sys_arm.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/arm/kernel/sys_arm.c	Wed Jul  4 14:56:44 2001
@@ -28,9 +28,9 @@
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 
-/*
- * Constant strings used in inlined functions in header files
- */
+extern unsigned long do_mremap(unsigned long addr, unsigned long old_len,
+			       unsigned long new_len, unsigned long flags,
+			       unsigned long new_addr);
 
 /*
  * sys_pipe() is the normal C calling standard for creating
diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/cats-pci.c linux/arch/arm/mach-footbridge/cats-pci.c
--- v2.4.6/linux/arch/arm/mach-footbridge/cats-pci.c	Sun Sep  3 11:19:11 2000
+++ linux/arch/arm/mach-footbridge/cats-pci.c	Wed Jul  4 15:43:05 2001
@@ -11,6 +11,7 @@
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
+#include <asm/hardware/dec21285.h>
 
 /* cats host-specific stuff */
 static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
@@ -31,7 +32,9 @@
 }
 
 struct hw_pci cats_pci __initdata = {
-	init:		dc21285_init,
-	swizzle:	no_swizzle,
-	map_irq:	cats_map_irq,
+	setup_resources:	dc21285_setup_resources,
+	init:			dc21285_init,
+	mem_offset:		DC21285_PCI_MEM,
+	swizzle:		no_swizzle,
+	map_irq:		cats_map_irq,
 };
diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/ebsa285-pci.c linux/arch/arm/mach-footbridge/ebsa285-pci.c
--- v2.4.6/linux/arch/arm/mach-footbridge/ebsa285-pci.c	Sun Sep  3 11:19:11 2000
+++ linux/arch/arm/mach-footbridge/ebsa285-pci.c	Wed Jul  4 15:43:05 2001
@@ -11,6 +11,7 @@
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
+#include <asm/hardware/dec21285.h>
 
 static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI };
 
@@ -33,7 +34,9 @@
 }
 
 struct hw_pci ebsa285_pci __initdata = {
-	init:		dc21285_init,
-	swizzle:	ebsa285_swizzle,
-	map_irq:	ebsa285_map_irq,
+	setup_resources:	dc21285_setup_resources,
+	init:			dc21285_init,
+	mem_offset:		DC21285_PCI_MEM,
+	swizzle:		ebsa285_swizzle,
+	map_irq:		ebsa285_map_irq,
 };
diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/netwinder-pci.c linux/arch/arm/mach-footbridge/netwinder-pci.c
--- v2.4.6/linux/arch/arm/mach-footbridge/netwinder-pci.c	Sun Sep  3 11:19:11 2000
+++ linux/arch/arm/mach-footbridge/netwinder-pci.c	Wed Jul  4 15:43:05 2001
@@ -11,6 +11,7 @@
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
+#include <asm/hardware/dec21285.h>
 
 /* netwinder host-specific stuff */
 static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
@@ -48,7 +49,9 @@
 }
 
 struct hw_pci netwinder_pci __initdata = {
-	init:		dc21285_init,
-	swizzle:	no_swizzle,
-	map_irq:	netwinder_map_irq,
+	setup_resources:	dc21285_setup_resources,
+	init:			dc21285_init,
+	mem_offset:		DC21285_PCI_MEM,
+	swizzle:		no_swizzle,
+	map_irq:		netwinder_map_irq,
 };
diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/personal-pci.c linux/arch/arm/mach-footbridge/personal-pci.c
--- v2.4.6/linux/arch/arm/mach-footbridge/personal-pci.c	Sun Sep  3 11:19:11 2000
+++ linux/arch/arm/mach-footbridge/personal-pci.c	Wed Jul  4 15:43:05 2001
@@ -11,6 +11,7 @@
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
+#include <asm/hardware/dec21285.h>
 
 static int irqmap_personal_server[] __initdata = {
 	IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0,
@@ -37,7 +38,9 @@
 }
 
 struct hw_pci personal_server_pci __initdata = {
-	init:		dc21285_init,
-	swizzle:	no_swizzle,
-	map_irq:	personal_server_map_irq,
+	setup_resources:	dc21285_setup_resources,
+	init:			dc21285_init,
+	mem_offset:		DC21285_PCI_MEM,
+	swizzle:		no_swizzle,
+	map_irq:		personal_server_map_irq,
 };
diff -u --recursive --new-file v2.4.6/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types
--- v2.4.6/linux/arch/arm/tools/mach-types	Tue Jul  3 17:08:18 2001
+++ linux/arch/arm/tools/mach-types	Wed Jul  4 14:56:44 2001
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Sun Jun 17 00:53:17 2001
+# Last update: Wed Jul 4 20:04:11 2001
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -91,12 +91,17 @@
 empeg			SA1100_EMPEG		EMPEG			79
 adi_eb			ARCH_I80200FCC		I80200FCC		80
 itt_cpb			SA1100_ITT_CPB		ITT_CPB			81
-sa1110_svc		ARCH_SA1110_SVC		SA1110_SVC		82
+svc			SA1100_SVC		SVC			82
 alpha2			SA1100_ALPHA2		ALPHA2			84
 alpha1			SA1100_ALPHA1		ALPHA1			85
 netarm			ARCH_NETARM		NETARM			86
 simpad			SA1100_SIMPAD		SIMPAD			87
 pda1			ARCH_PDA1		PDA1			88
 lubbock			ARCH_LUBBOCK		LUBBOCK			89
+aniko			ARCH_ANIKO		ANIKO			90
+clep7212		ARCH_CLEP7212		CLEP7212		91
+cs89712			ARCH_CS89712		CS89712			92
+weararm			SA1100_WEARARM		WEARARM			93
+possio_px		SA1100_POSSIO_PX	POSSIO_PX		94
 
 # The following are unallocated
diff -u --recursive --new-file v2.4.6/linux/arch/cris/Makefile linux/arch/cris/Makefile
--- v2.4.6/linux/arch/cris/Makefile	Tue May  1 16:04:56 2001
+++ linux/arch/cris/Makefile	Wed Jul  4 11:50:38 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $
+# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -49,7 +49,12 @@
 
 HEAD := arch/cris/kernel/head.o
 
-SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers arch/cris/boot/rescue
+SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers
+ifdef CONFIG_ETRAX_AXISFLASHMAP
+# only build this if axis flash map is used, because they depend on
+# each others config options
+SUBDIRS += arch/cris/boot/rescue
+endif
 CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o
 LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
 LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
diff -u --recursive --new-file v2.4.6/linux/arch/cris/config.in linux/arch/cris/config.in
--- v2.4.6/linux/arch/cris/config.in	Tue May  1 16:04:56 2001
+++ linux/arch/cris/config.in	Wed Jul  4 11:50:38 2001
@@ -18,11 +18,10 @@
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
 
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
-fi
 
 bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB
 
@@ -38,9 +37,9 @@
 	 Etrax-100-LX-v2	CONFIG_ETRAX100LX_V2	\
 	 Etrax-100-LX-for-xsim-simulator   CONFIG_SVINTO_SIM" Etrax-100-LX-v1
 
-# For both LX version 1 and the current simulator we enable the low VM mapping
+# Etrax100 LX v1 has a MMU "feature" requiring a low mapping
 
-if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then
+if [ "$CONFIG_ETRAX100LX" = "y" ]; then
 	define_bool CONFIG_CRIS_LOW_MAP y
 	define_hex  CONFIG_ETRAX_DRAM_VIRTUAL_BASE 60000000
 else
@@ -98,7 +97,7 @@
 hex 'R_WAITSTATES' CONFIG_ETRAX_DEF_R_WAITSTATES 95a6
 hex 'R_BUS_CONFIG' CONFIG_ETRAX_DEF_R_BUS_CONFIG 104
 
-bool 'SDRAM support' CONFIG_ETRAX_SDRAM n
+bool 'SDRAM support' CONFIG_ETRAX_SDRAM
 if [ "$CONFIG_ETRAX_SDRAM" = "n" ]; then
 	hex 'R_DRAM_CONFIG' CONFIG_ETRAX_DEF_R_DRAM_CONFIG 1a200040
 	hex 'R_DRAM_TIMING' CONFIG_ETRAX_DEF_R_DRAM_TIMING 5611
@@ -115,6 +114,12 @@
 hex 'R_PORT_PB_DIR' CONFIG_ETRAX_DEF_R_PORT_PB_DIR 00
 hex 'R_PORT_PB_DATA' CONFIG_ETRAX_DEF_R_PORT_PB_DATA ff
 
+bool 'Software Shutdown Support' CONFIG_ETRAX_SOFT_SHUTDOWN
+if [ "$CONFIG_ETRAX_SOFT_SHUTDOWN" = "y" ]; then
+   int 'Shutdown bit on port CSP0' CONFIG_ETRAX_SHUTDOWN_BIT 12
+   int 'Power button bit on port G' CONFIG_ETRAX_POWERBUTTON_BIT 25
+fi
+
 endmenu
 
 # bring in Etrax built-in drivers
@@ -164,7 +169,7 @@
 
 source drivers/ieee1394/Config.in
 
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
@@ -214,8 +219,6 @@
 source drivers/media/Config.in
 
 source fs/Config.in
-
-source drivers/char/Config.in
 
 mainmenu_option next_comment
 comment 'Sound'
diff -u --recursive --new-file v2.4.6/linux/arch/cris/defconfig linux/arch/cris/defconfig
--- v2.4.6/linux/arch/cris/defconfig	Tue May  1 16:04:56 2001
+++ linux/arch/cris/defconfig	Wed Jul  4 11:50:38 2001
@@ -2,6 +2,8 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 
 #
 # Code maturity level options
@@ -13,8 +15,9 @@
 #
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_JAVA is not set
 # CONFIG_ETRAX_KGDB is not set
 # CONFIG_ETRAX_WATCHDOG is not set
 
@@ -27,16 +30,30 @@
 CONFIG_CRIS_LOW_MAP=y
 CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000
 CONFIG_ETRAX_DRAM_SIZE=8
-CONFIG_ETRAX_FLASH_LENGTH=2
 CONFIG_ETRAX_FLASH_BUSWIDTH=2
 CONFIG_ETRAX_PA_LEDS=y
 # CONFIG_ETRAX_PB_LEDS is not set
-# CONFIG_ETRAX_90000000_LEDS is not set
+# CONFIG_ETRAX_CSP0_LEDS is not set
 # CONFIG_ETRAX_NO_LEDS is not set
 CONFIG_ETRAX_LED1G=2
 CONFIG_ETRAX_LED1R=2
 CONFIG_ETRAX_LED2G=2
 CONFIG_ETRAX_LED2R=2
+CONFIG_ETRAX_LED3R=2
+CONFIG_ETRAX_LED3G=2
+CONFIG_ETRAX_LED4R=2
+CONFIG_ETRAX_LED4G=2
+CONFIG_ETRAX_LED5R=2
+CONFIG_ETRAX_LED5G=2
+CONFIG_ETRAX_LED6R=2
+CONFIG_ETRAX_LED6G=2
+CONFIG_ETRAX_LED7R=2
+CONFIG_ETRAX_LED7G=2
+CONFIG_ETRAX_LED8Y=2
+CONFIG_ETRAX_LED9Y=2
+CONFIG_ETRAX_LED10Y=2
+CONFIG_ETRAX_LED11Y=2
+CONFIG_ETRAX_LED12R=2
 CONFIG_ETRAX_DEBUG_PORT0=y
 # CONFIG_ETRAX_DEBUG_PORT1 is not set
 # CONFIG_ETRAX_DEBUG_PORT2 is not set
@@ -55,13 +72,17 @@
 CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00
 CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e
 CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3
+# CONFIG_ETRAX_SOFT_SHUTDOWN is not set
 
 #
-# Drivers for Etrax built-in interfaces
+# Drivers for ETRAX 100LX built-in interfaces
 #
 CONFIG_ETRAX_ETHERNET=y
 CONFIG_NET_ETHERNET=y
-CONFIG_ETRAX_SERIAL=y
+# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
+CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
+C# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set
+ONFIG_ETRAX_SERIAL=y
 # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set
 CONFIG_ETRAX_SERIAL_PORT1=y
 # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set
@@ -71,6 +92,7 @@
 # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set
 # CONFIG_ETRAX_IDE is not set
 CONFIG_ETRAX_AXISFLASHMAP=y
+CONFIG_ETRAX_PTABLE_SECTOR=65536
 CONFIG_MTD=y
 CONFIG_MTD_CFI=y
 # CONFIG_MTD_CFI_INTELEXT is not set
@@ -80,6 +102,7 @@
 CONFIG_MTD_BLOCK=y
 CONFIG_ETRAX_I2C=y
 CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y
+# CONFIG_ETRAX_I2C_EEPROM is not set
 CONFIG_ETRAX_GPIO=y
 CONFIG_ETRAX_PA_BUTTON_BITMASK=02
 CONFIG_ETRAX_PA_CHANGEABLE_DIR=00
@@ -87,21 +110,35 @@
 CONFIG_ETRAX_PB_CHANGEABLE_DIR=00
 CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF
 # CONFIG_ETRAX_USB_HOST is not set
+# CONFIG_USB is not set
+# CONFIG_ETRAX_DS1302 is not set
 
 #
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
 # CONFIG_MTD_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOCPROBE is not set
+
+#
+# RAM/ROM Device Drivers
+#
 # CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_MTDRAM is not set
+
+#
+# Linearly Mapped Flash Device Drivers
+#
 CONFIG_MTD_CFI=y
 # CONFIG_MTD_CFI_GEOMETRY is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
@@ -112,6 +149,7 @@
 # CONFIG_MTD_NORA is not set
 # CONFIG_MTD_PNC2000 is not set
 # CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_SC520CDP is not set
 # CONFIG_MTD_SBC_MEDIAGX is not set
 # CONFIG_MTD_ELAN_104NC is not set
 # CONFIG_MTD_SA1100 is not set
@@ -121,8 +159,16 @@
 # CONFIG_MTD_MIXMEM is not set
 # CONFIG_MTD_OCTAGON is not set
 # CONFIG_MTD_VMAX is not set
+
+#
+# NAND Flash Device Drivers
+#
 # CONFIG_MTD_NAND is not set
 # CONFIG_MTD_NAND_SPIA is not set
+
+#
+# User Modules And Translation Layers
+#
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in
--- v2.4.6/linux/arch/cris/drivers/Config.in	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/Config.in	Wed Jul  4 11:50:38 2001
@@ -6,10 +6,21 @@
 # this is just so that the user does not have to go into the
 # normal ethernet driver section just to enable ethernetworking
   define_bool CONFIG_NET_ETHERNET y
+  
+  choice 'Network LED behavior' \
+  "LED_on_when_link      CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK    \
+   LED_on_when_activity  CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" \
+     LED_on_when_activity
+
 else
   define_bool CONFIG_NET_ETHERNET n
 fi
 
+bool 'Etrax Ethernet slave support (over lp0/1)' CONFIG_ETRAX_ETHERNET_LPSLAVE
+if [ "$CONFIG_ETRAX_ETHERNET_LPSLAVE" = "y" ]; then
+  bool '  Slave has its own LEDs' CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
+fi 
+
 bool 'Serial-port support' CONFIG_ETRAX_SERIAL
 if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
   comment '  Port 0 is always enabled'
@@ -99,7 +110,7 @@
 	define_bool CONFIG_BLK_DEV_IDEDMA y
 	define_bool CONFIG_DMA_NONPCI y
 	
-	int 'Delay for drives to regain consciousness' CONFIG_IDE_DELAY 15
+	int 'Delay for drives to regain consciousness' CONFIG_ETRAX_IDE_DELAY 15
 	
 	choice 'IDE reset pin' \
   	"Port_PB_Bit_7  CONFIG_ETRAX_IDE_PB7_RESET\
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile
--- v2.4.6/linux/arch/cris/drivers/Makefile	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/Makefile	Wed Jul  4 11:50:38 2001
@@ -7,18 +7,21 @@
 obj-y :=
 
 
-obj-$(CONFIG_ETRAX_ETHERNET)           += ethernet.o
-obj-$(CONFIG_ETRAX_SERIAL)             += serial.o
-obj-$(CONFIG_ETRAX_IDE)                += ide.o
-obj-$(CONFIG_ETRAX_AXISFLASHMAP)       += axisflashmap.o
-obj-$(CONFIG_ETRAX_I2C) 	       += i2c.o
-obj-$(CONFIG_ETRAX_I2C_EEPROM)         += eeprom.o
-obj-$(CONFIG_ETRAX_GPIO) 	       += gpio.o
-obj-$(CONFIG_ETRAX_USB_HOST)           += usb-host.o
-obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
-obj-$(CONFIG_ETRAX_PARPORT)            += parport.o
-obj-$(CONFIG_ETRAX_DS1302)             += ds1302.o
+obj-$(CONFIG_ETRAX_ETHERNET)            += ethernet.o
+obj-$(CONFIG_ETRAX_SERIAL)              += serial.o
+obj-$(CONFIG_ETRAX_IDE)                 += ide.o
+obj-$(CONFIG_ETRAX_AXISFLASHMAP)        += axisflashmap.o
+obj-$(CONFIG_ETRAX_I2C) 	        += i2c.o
+obj-$(CONFIG_ETRAX_I2C_EEPROM)          += eeprom.o
+obj-$(CONFIG_ETRAX_GPIO) 	        += gpio.o
+obj-$(CONFIG_ETRAX_USB_HOST)            += usb-host.o
+obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)  += sync_serial.o
+obj-$(CONFIG_ETRAX_PARPORT)             += parport.o
+obj-$(CONFIG_ETRAX_DS1302)              += ds1302.o
 
 
+obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
+subdir-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave
 
 include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c
--- v2.4.6/linux/arch/cris/drivers/axisflashmap.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/axisflashmap.c	Wed Jul  4 11:50:38 2001
@@ -11,6 +11,23 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.12  2001/06/11 09:50:30  jonashg
+ * Oops, 2MB is 0x200000 bytes.
+ *
+ * Revision 1.11  2001/06/08 11:39:44  jonashg
+ * Changed sizes and offsets in axis_default_partitions to use
+ * CONFIG_ETRAX_PTABLE_SECTOR.
+ *
+ * Revision 1.10  2001/05/29 09:42:03  jonashg
+ * Use macro for end marker length instead of sizeof.
+ *
+ * Revision 1.9  2001/05/29 08:52:52  jonashg
+ * Gave names to the magic fours (size of the ptable end marker).
+ *
+ * Revision 1.8  2001/05/28 15:36:20  jonashg
+ * * Removed old comment about ptable location in flash (it's a CONFIG_ option).
+ * * Variable ptable was initialized twice to the same value.
+ *
  * Revision 1.7  2001/04/05 13:41:46  markusl
  * Updated according to review remarks
  *
@@ -130,6 +147,10 @@
 #define MAX_PARTITIONS         7  
 #define NUM_DEFAULT_PARTITIONS 3
 
+/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+ * size of one flash block and "filesystem"-partition needs 5 blocks to be able
+ * to use JFFS.
+ */
 static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
 	{
 		name: "boot firmware",
@@ -138,13 +159,13 @@
 	},
 	{
 		name: "kernel",
-		size: 0x1a0000,
+		size: 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
 		offset: CONFIG_ETRAX_PTABLE_SECTOR
 	},
 	{
 		name: "filesystem",
-		size: 0x50000,
-		offset: (0x1a0000 + CONFIG_ETRAX_PTABLE_SECTOR)
+		size: 5 * CONFIG_ETRAX_PTABLE_SECTOR,
+		offset: 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
 	}
 };
 
@@ -223,21 +244,17 @@
 
 	mymtd->module = THIS_MODULE;
 
-	/* The partition-table is at an offset within the second 
-	 * sector of the flash. We _define_ this to be at offset 64k
-	 * even if the actual sector-size in the flash changes.. for
-	 * now at least.
-	 */
-
 	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
 		CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
 	pidx++;  /* first partition is always set to the default */
 
 	if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
 	    && (ptable_head->size <
-		(MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4))
+		(MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
+		PARTITIONTABLE_END_MARKER_SIZE))
 	    && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
-				  ptable_head->size - 4)
+				  ptable_head->size -
+				  PARTITIONTABLE_END_MARKER_SIZE)
 		== PARTITIONTABLE_END_MARKER)) {
 		/* Looks like a start, sane length and end of a
 		 * partition table, lets check csum etc.
@@ -268,9 +285,6 @@
 		ptable_ok = (csum == ptable_head->checksum);
 
 		/* Read the entries and use/show the info.  */
-		ptable = (struct partitiontable_entry *)
-			((unsigned long)ptable_head + sizeof(*ptable_head));
-		
 		printk(" Found %s partition table at 0x%08lX-0x%08lX.\n",
 		       (ptable_ok ? "valid" : "invalid"),
 		       (unsigned long)ptable_head,
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/ds1302.c linux/arch/cris/drivers/ds1302.c
--- v2.4.6/linux/arch/cris/drivers/ds1302.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/ds1302.c	Wed Jul  4 11:50:38 2001
@@ -7,6 +7,32 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.11  2001/06/14 12:35:52  jonashg
+*! The ATA hack is back. It is unfortunately the only way to set g27 to output.
+*!
+*! Revision 1.9  2001/06/14 10:00:14  jonashg
+*! No need for tempudelay to be inline anymore (had to adjust the usec to
+*! loops conversion because of this to make it slow enough to be a udelay).
+*!
+*! Revision 1.8  2001/06/14 08:06:32  jonashg
+*! Made tempudelay delay usecs (well, just a tad more).
+*!
+*! Revision 1.7  2001/06/13 14:18:11  jonashg
+*! Only allow processes with SYS_TIME capability to set time and charge.
+*!
+*! Revision 1.6  2001/06/12 15:22:07  jonashg
+*! * Made init function __init.
+*! * Parameter to out_byte() is unsigned char.
+*! * The magic number 42 has got a name.
+*! * Removed comment about /proc (nothing is exported there).
+*!
+*! Revision 1.5  2001/06/12 14:35:13  jonashg
+*! Gave the module a name and added it to printk's.
+*!
+*! Revision 1.4  2001/05/31 14:53:40  jonashg
+*! Made tempudelay() inline so that the watchdog doesn't reset (see
+*! function comment).
+*!
 *! Revision 1.3  2001/03/26 16:03:06  bjornw
 *! Needs linux/config.h
 *!
@@ -56,13 +82,14 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $
+*! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $
 *!
 *!***************************************************************************/
 
 #include <linux/config.h>
 
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/miscdevice.h>
@@ -76,13 +103,15 @@
 
 #define RTC_MAJOR_NR 121 /* local major, change later */
 
+static const char ds1302_name[] = "ds1302";
+
 /* The DS1302 might be connected to different bits on different products. 
  * It has three signals - SDA, SCL and RST. RST and SCL are always outputs,
  * but SDA can have a selected direction.
  * For now, only PORT_PB is hardcoded.
  */
 
-/* The RST bit may be on either the Generic Port or Port PB */
+/* The RST bit may be on either the Generic Port or Port PB. */
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
 #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
 #define TK_RST_DIR(x)
@@ -106,21 +135,23 @@
  * (used in udelay) is not set when functions here are called from time.c 
  */
 
-static void tempudelay(int time) 
+static void tempudelay(int usecs) 
 {
-	int i;
-	for(i = 0; i < time * 10000; i++);	
+	volatile int loops;
+
+	for(loops = usecs * 12; loops > 0; loops--)
+		/* nothing */;	
 }
 
 
-/* send 8 bits */
+/* Send 8 bits. */
 static void
-out_byte(int x) 
+out_byte(unsigned char x) 
 {
 	int i;
 	TK_SDA_DIR(1);
 	for (i = 8; i--;) {
-		/* the chip latches incoming bits on the rising edge of SCL */
+		/* The chip latches incoming bits on the rising edge of SCL. */
 		TK_SCL_OUT(0);
 		TK_SDA_OUT(x & 1);
 		tempudelay(1);
@@ -138,7 +169,7 @@
 	int i;
 
 	/* Read byte. Bits come LSB first, on the falling edge of SCL.
-	 * Assume SDA is in input direction already
+	 * Assume SDA is in input direction already.
 	 */
 	TK_SDA_DIR(0);
 
@@ -154,7 +185,7 @@
 	return x;
 }
 
-/* prepares for a transaction by de-activating RST (active-low) */
+/* Prepares for a transaction by de-activating RST (active-low). */
 
 static void
 start(void) 
@@ -166,7 +197,7 @@
 	TK_RST_OUT(1);	
 }
 
-/* ends a transaction by taking RST active again */
+/* Ends a transaction by taking RST active again. */
 
 static void
 stop(void) 
@@ -175,7 +206,7 @@
 	TK_RST_OUT(0);
 }
 
-/* enable writing */
+/* Enable writing. */
 
 static void
 ds1302_wenable(void) 
@@ -186,7 +217,7 @@
 	stop();
 }
 
-/* disable writing */
+/* Disable writing. */
 
 static void
 ds1302_wdisable(void) 
@@ -197,7 +228,9 @@
 	stop();
 }
 
-/* probe for the chip by writing something to its RAM and try reading it back */
+/* Probe for the chip by writing something to its RAM and try reading it back. */
+
+#define MAGIC_PATTERN 0x42
 
 static int
 ds1302_probe(void) 
@@ -208,36 +241,36 @@
 	TK_SCL_DIR(1);
 	TK_SDA_DIR(0);
 	
-	/* try to talk to timekeeper */
+	/* Try to talk to timekeeper. */
 
 	ds1302_wenable();  
 	start();
 	out_byte(0xc0); /* write RAM byte 0 */	
-	out_byte(0x42); /* write something magic */
+	out_byte(MAGIC_PATTERN); /* write something magic */
 	start();
 	out_byte(0xc1); /* read RAM byte 0 */
 
-	if((res = in_byte()) == 0x42) {
+	if((res = in_byte()) == MAGIC_PATTERN) {
 		char buf[100];
 		stop();
 		ds1302_wdisable();
-		printk("DS1302 RTC found.\n");
-                printk("SDA, SCL, RST on PB%i, PB%i, %s%i\n",
-                       CONFIG_ETRAX_DS1302_SDABIT,
-                       CONFIG_ETRAX_DS1302_SCLBIT,
+		printk("%s: RTC found.\n", ds1302_name);
+		printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",
+		       ds1302_name,
+		       CONFIG_ETRAX_DS1302_SDABIT,
+		       CONFIG_ETRAX_DS1302_SCLBIT,
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
-                       "GENIO",
+		       "GENIO",
 #else
-                       "PB",
+		       "PB",
 #endif
-                       CONFIG_ETRAX_DS1302_RSTBIT
-                       );
+		       CONFIG_ETRAX_DS1302_RSTBIT);
                 get_rtc_status(buf);
                 printk(buf);
 		retval = 1;
 	} else {
 		stop();
-		printk("DS1302 RTC not found.\n");
+		printk("%s: RTC not found.\n", ds1302_name);
 		retval = 0;
 	}
 
@@ -245,7 +278,7 @@
 }
 
 
-/* read a byte from the selected register in the DS1302 */
+/* Read a byte from the selected register in the DS1302. */
 
 unsigned char
 ds1302_readreg(int reg) 
@@ -253,21 +286,21 @@
 	unsigned char x;
 
 	start();
-	out_byte(0x81 | (reg << 1)); /* Read register */
+	out_byte(0x81 | (reg << 1)); /* read register */
 	x = in_byte();
 	stop();
 
 	return x;
 }
 
-/* write a byte to the selected register */
+/* Write a byte to the selected register. */
 
 void
 ds1302_writereg(int reg, unsigned char val) 
 {
 	ds1302_wenable();
 	start();
-	out_byte(0x80 | (reg << 1)); /* Write register */
+	out_byte(0x80 | (reg << 1)); /* write register */
 	out_byte(val);
 	stop();
 	ds1302_wdisable();
@@ -311,7 +344,7 @@
 static unsigned char days_in_mo[] = 
     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
-/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date) */
+/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
 
 static int
 rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -320,7 +353,7 @@
         unsigned long flags;
 
 	switch(cmd) {
-		case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+		case RTC_RD_TIME:	/* read the time/date from RTC	*/
 		{
 			struct rtc_time rtc_tm;
 						
@@ -330,16 +363,16 @@
 			return 0;
 		}
 
-		case RTC_SET_TIME:	/* Set the RTC */
+		case RTC_SET_TIME:	/* set the RTC */
 		{
 			struct rtc_time rtc_tm;
 			unsigned char mon, day, hrs, min, sec, leap_yr;
 			unsigned char save_control, save_freq_select;
 			unsigned int yrs;
-#if 0
-			if (!suser())
-				return -EACCES;
-#endif			
+
+			if (!capable(CAP_SYS_TIME))
+				return -EPERM;
+
 			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
 				return -EFAULT;    	
 
@@ -387,21 +420,21 @@
 			CMOS_WRITE(sec, RTC_SECONDS);
 			restore_flags(flags);
 
-			/* notice that at this point, the RTC is updated but the kernel
-			 * is still running with the old time. you need to set that
-			 * separately with settimeofday or adjtimex.
+			/* Notice that at this point, the RTC is updated but
+			 * the kernel is still running with the old time.
+			 * You need to set that separately with settimeofday
+			 * or adjtimex.
 			 */
 			return 0;
 		}
 
-		case RTC_SET_CHARGE: /* Set the RTC TRICKLE CHARGE register */
+		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
 		{
 			int tcs_val;                        
 			unsigned char save_control, save_freq_select;
-#if 0
-			if (!suser())
-				return -EACCES;
-#endif
+
+			if (!capable(CAP_SYS_TIME))
+				return -EPERM;
 			
 			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
 				return -EFAULT;
@@ -415,10 +448,6 @@
 	}
 }
 
-/*
- *	Info exported via "/proc/rtc".
- */
-
 int
 get_rtc_status(char *buf) 
 {
@@ -444,45 +473,41 @@
 }
 
 
-/*
- *	The various file operations we support.
- */
+/* The various file operations we support. */
 
 static struct file_operations rtc_fops = {
         owner:          THIS_MODULE,
         ioctl:          rtc_ioctl,	
 }; 
 
-/* just probe for the RTC and register the device to handle the ioctl needed */
+/* Just probe for the RTC and register the device to handle the ioctl needed. */
 
-int
+int __init
 ds1302_init(void) 
 { 
-  
- /* Ugly hack to handle both 2100 and 2400 hardware.
-    Remove...
- */
-	if(!ds1302_probe()) {
+	if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
-    	/*
-     	* Make sure that R_GEN_CONFIG is 
-     	* setup correct.
-     	*/
-    		genconfig_shadow = ( (genconfig_shadow & ~IO_MASK(R_GEN_CONFIG, ata) ) | 
-                           ( IO_STATE( R_GEN_CONFIG, ata, select ) ) );    
+		/*
+		 * The only way to set g27 to output is to enable ATA.
+		 *
+		 * Make sure that R_GEN_CONFIG is setup correct.
+		 */
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, ata))
+				   | 
+				   (IO_STATE(R_GEN_CONFIG, ata, select)));    
     		*R_GEN_CONFIG = genconfig_shadow;
-    		if(!ds1302_probe())
+    		if (!ds1302_probe())
       			return -1;
 #else
     		return -1;
 #endif
   	}
   
-	if (register_chrdev(RTC_MAJOR_NR, "rtc", &rtc_fops)) {
-		printk("unable to get major %d for rtc\n", RTC_MAJOR_NR);
+	if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
+		printk(KERN_INFO "%s: unable to get major %d for rtc\n", 
+		       ds1302_name, RTC_MAJOR_NR);
 		return -1;
 	}
 	return 0;
 }
-
-
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c
--- v2.4.6/linux/arch/cris/drivers/eeprom.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/eeprom.c	Wed Jul  4 11:50:38 2001
@@ -1,32 +1,12 @@
-/*!**************************************************************************
+/*!*****************************************************************************
 *!
-*!  FILE NAME:      e100eeprom.c
-*!
-*!  DESCRIPTION:    Implements an interface for i2c compatible eeproms to run
-*!                  under linux.
-*!                  Supports 2k, 8k(?) and 16k
-*!                  Uses adaptive timing adjustents by Johan.Adolfsson@axis.com
-*!                  Probing results:
-*!                    8k or not is detected (the assumes 2k or 16k)
-*!                    2k or 16k detected using test reads and writes.
-*!
-*!  FUNCTIONS:
-*!
-*!  (Exported)
-*!              eeprom_init()
-*!
-*!  (Local)
-*!
-*!              eeprom_open()
-*!              eeprom_lseek()
-*!              eeprom_read()
-*!              eeprom_write()
-*!              eeprom_close()
-*!              eeprom_address()
-*!              eeprom_disable_write_protect()
-*!
-*!
-*!  $Id: eeprom.c,v 1.3 2001/03/19 16:04:46 markusl Exp $
+*!  Implements an interface for i2c compatible eeproms to run under linux.
+*!  Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by
+*!  Johan.Adolfsson@axis.com
+*!
+*!  Probing results:
+*!    8k or not is detected (the assumes 2k or 16k)
+*!    2k or 16k detected using test reads and writes.
 *!
 *!------------------------------------------------------------------------
 *!  HISTORY
@@ -40,6 +20,13 @@
 *!                                  in the spin-lock.
 *!
 *!  $Log: eeprom.c,v $
+*!  Revision 1.5  2001/06/14 14:39:51  jonashg
+*!  Forgot to use name when registering the driver.
+*!
+*!  Revision 1.4  2001/06/14 14:35:47  jonashg
+*!  * Gave driver a name and used it in printk's.
+*!  * Cleanup.
+*!
 *!  Revision 1.3  2001/03/19 16:04:46  markusl
 *!  Fixed init of fops struct
 *!
@@ -64,9 +51,7 @@
 *!
 *!
 *!        (c) 1999 Axis Communications AB, Lund, Sweden
-*!**************************************************************************/
-
-/********************** INCLUDE FILES SECTION ******************************/
+*!*****************************************************************************/
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -76,7 +61,6 @@
 #include <linux/delay.h>
 #include "i2c.h"
 
-/********************** CONSTANT AND MACRO SECTION *************************/
 #define D(x) 
 
 /* If we should use adaptive timing or not: */
@@ -86,9 +70,8 @@
 #define EEPROM_MINOR_NR 0
 
 #define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
-/*
- *  this one defines how many times to try when eeprom fails.
- */
+
+/* This one defines how many times to try when eeprom fails. */
 #define EEPROM_RETRIES 10
 
 #define EEPROM_2KB (2 * 1024)
@@ -98,8 +81,6 @@
 
 #define i2c_delay(x) udelay(x)
 
-/********************** TYPE DEFINITION SECTION ****************************/
-
 /*
  *  This structure describes the attached eeprom chip.
  *  The values are probed for.
@@ -110,51 +91,42 @@
   unsigned long size;
   unsigned long sequential_write_pagesize;
   unsigned char select_cmd;
-  unsigned long usec_delay_writecycles; /* Min time between write cycles (up to 10ms for some models) */
-  unsigned long int usec_delay_step; /* For adaptive algorithm */
+  unsigned long usec_delay_writecycles; /* Min time between write cycles
+					   (up to 10ms for some models) */
+  unsigned long usec_delay_step; /* For adaptive algorithm */
   int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */
   
   /* this one is to keep the read/write operations atomic */
   wait_queue_head_t wait_q;
   int busy;
   int retry_cnt_addr; /* Used to keep track of number of retries for
-                     adaptive timing adjustments */
+                         adaptive timing adjustments */
   int retry_cnt_read;
-
-  
-  
 };
 
-/********************** LOCAL FUNCTION DECLARATION SECTION *****************/
-
-static int  eeprom_open (struct inode * inode, struct file * file);
+static int  eeprom_open(struct inode * inode, struct file * file);
 static loff_t  eeprom_lseek(struct file * file, loff_t offset, int orig);
-static ssize_t  eeprom_read (struct file * file, char * buf, size_t count, loff_t *off);
-static ssize_t  eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off);
+static ssize_t  eeprom_read(struct file * file, char * buf, size_t count,
+                            loff_t *off);
+static ssize_t  eeprom_write(struct file * file, const char * buf, size_t count,
+                             loff_t *off);
 static int eeprom_close(struct inode * inode, struct file * file);
 
 static int  eeprom_address(unsigned long addr);
 static int  read_from_eeprom(char * buf, int count);
-static int eeprom_write_buf(unsigned long int addr,
-                            const char * buf, int count);
+static int eeprom_write_buf(unsigned long addr, const char * buf, int count);
 static int eeprom_read_buf(unsigned long addr,
                            char * buf, int count);
 
 static void eeprom_disable_write_protect(void);
 
 
-/********************** GLOBAL VARIABLE DECLARATION SECTION ****************/
-
-/********************** LOCAL VARIABLE DECLARATION SECTION *****************/
+static const char eeprom_name[] = "eeprom";
 
 /* chip description */
 static struct eeprom_type eeprom;
 
-/*
- *  This is the exported file-operations structure
- *  for this device.
- */
-
+/* This is the exported file-operations structure for this device. */
 struct file_operations eeprom_fops =
 {
   llseek:  eeprom_lseek,
@@ -164,29 +136,7 @@
   release: eeprom_close
 };
 
-/********************** FUNCTION DEFINITION SECTION ************************/
-
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_init
-*#                                                            
-*# PARAMETERS   : none
-*#                                                            
-*# RETURNS      : 0 if OK
-*#                                                            
-*# SIDE EFFECTS : 
-*#                                                            
-*# DESCRIPTION  : eeprom init call. Probes for different eeprom models.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version               
-*# Sep 03 1999  Edgar Iglesias  Updated probing. Added forced values.
-*#
-*#**************************************************************************/
+/* eeprom init call. Probes for different eeprom models. */
 
 int __init eeprom_init(void)
 {
@@ -198,9 +148,10 @@
 #else
 #define EETEXT "Assuming"
 #endif
-  if (register_chrdev(EEPROM_MAJOR_NR, "mem", &eeprom_fops))
+  if (register_chrdev(EEPROM_MAJOR_NR, eeprom_name, &eeprom_fops))
   {
-    printk("unable to get major %d for eeprom device\n", EEPROM_MAJOR_NR);
+    printk(KERN_INFO "%s: unable to get major %d for eeprom device\n",
+           eeprom_name, EEPROM_MAJOR_NR);
     return -1;
   }
   
@@ -213,7 +164,6 @@
    *        for all models. If you encounter problems the easiest way
    *        is probably to define your model within #ifdef's, and hard-
    *        code it.
-   *
    */
 
   eeprom.size = 0;
@@ -240,7 +190,6 @@
      * 2. if it doesn't differ - write diferent value to one of the locations,
      *    check the other - if content still is the same it's a 2k EEPROM,
      *    restore original data.
-     *    
      */
 #define LOC1 8
 #define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */
@@ -256,7 +205,7 @@
     }
     else
     {
-      printk("Failed to read in 2k mode!\n");  
+      printk(KERN_INFO "%s: Failed to read in 2k mode!\n", eeprom_name);  
     }
     
     /* 16k settings */
@@ -276,7 +225,7 @@
           if (memcmp(loc1, loc2, 4) != 0 )
           {
             /* It's 16k */
-            printk("16k detected in step 1\n");
+            printk(KERN_INFO "%s: 16k detected in step 1\n", eeprom_name);
             eeprom.size = EEPROM_16KB;     
             success = 1;
           }
@@ -299,7 +248,8 @@
                          LOC1, loc1, tmp));
                 if (memcmp(loc1, tmp, 4) != 0 )
                 {
-                  printk("read and write differs! Not 16kB\n");
+                  printk(KERN_INFO "%s: read and write differs! Not 16kB\n",
+                         eeprom_name);
                   loc1[0] = ~loc1[0];
                   
                   if (eeprom_write_buf(LOC1, loc1, 1) == 1)
@@ -308,7 +258,8 @@
                   }
                   else
                   {
-                    printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n");
+                    printk(KERN_INFO "%s: Restore 2k failed during probe,"
+                           " EEPROM might be corrupt!\n", eeprom_name);
                     
                   }
                   i2c_stop();
@@ -321,7 +272,8 @@
                   }
                   else
                   {
-                    printk("Failed to write back 2k start!\n");
+                    printk(KERN_INFO "%s: Failed to write back 2k start!\n",
+                           eeprom_name);
                   }
                   
                   eeprom.size = EEPROM_2KB;
@@ -338,7 +290,7 @@
                   {
                     /* Data the same, must be mirrored -> 2k */
                     /* Restore data */
-                    printk("2k detected in step 2\n");
+                    printk(KERN_INFO "%s: 2k detected in step 2\n", eeprom_name);
                     loc1[0] = ~loc1[0];
                     if (eeprom_write_buf(LOC1, loc1, 1) == 1)
                     {
@@ -346,7 +298,8 @@
                     }
                     else
                     {
-                      printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n");
+                      printk(KERN_INFO "%s: Restore 2k failed during probe,"
+                             " EEPROM might be corrupt!\n", eeprom_name);
                       
                     }
                     
@@ -354,7 +307,8 @@
                   }
                   else
                   {
-                    printk("16k detected in step 2\n");
+                    printk(KERN_INFO "%s: 16k detected in step 2\n",
+                           eeprom_name);
                     loc1[0] = ~loc1[0];
                     /* Data differs, assume 16k */
                     /* Restore data */
@@ -364,7 +318,8 @@
                     }
                     else
                     {
-                      printk("eeprom: Restore 16k failed during probe EEPROM might be corrupt!\n");
+                      printk(KERN_INFO "%s: Restore 16k failed during probe,"
+                             " EEPROM might be corrupt!\n", eeprom_name);
                     }
                     
                     eeprom.size = EEPROM_16KB;
@@ -376,7 +331,7 @@
         } /* address LOC1 */
         if (!success)
         {
-          printk("eeprom: Probing failed!, using 2KB!\n");
+          printk(KERN_INFO "%s: Probing failed!, using 2KB!\n", eeprom_name);
           eeprom.size = EEPROM_2KB;               
         }
       } /* read */
@@ -418,23 +373,23 @@
   switch(eeprom.size)
   {
    case (EEPROM_2KB):
-     printk("e100eeprom: " EETEXT " i2c compatible 2Kb eeprom.\n");
+     printk("%s: " EETEXT " i2c compatible 2Kb eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 16;
      eeprom.select_cmd = 0xA0;
      break;
    case (EEPROM_8KB):
-     printk("e100eeprom: " EETEXT " i2c compatible 8Kb eeprom.\n");
+     printk("%s: " EETEXT " i2c compatible 8Kb eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 16;
      eeprom.select_cmd = 0x80;
      break;
    case (EEPROM_16KB):
-     printk("e100eeprom: " EETEXT " i2c compatible 16Kb eeprom.\n");
+     printk("%s: " EETEXT " i2c compatible 16Kb eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 64;
      eeprom.select_cmd = 0xA0;     
      break;
    default:
      eeprom.size = 0;
-     printk("e100eeprom: Did not find a supported eeprom\n");
+     printk("%s: Did not find a supported eeprom\n", eeprom_name);
      break;
   }
 
@@ -445,28 +400,7 @@
   return 0;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_open
-*#                                                            
-*# PARAMETERS   : inode    : Pointer to the inode
-*#                file     : Pointer to the file
-*#                                                            
-*# RETURNS      : 0 if OK
-*#                                                            
-*# SIDE EFFECTS : 
-*#                                                            
-*# DESCRIPTION  : Opens the device.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version               
-*# Sep 03 1999  Edgar Iglesias  Removed users check.
-*#
-*#**************************************************************************/
+/* Opens the device. */
 
 static int eeprom_open(struct inode * inode, struct file * file)
 {
@@ -486,29 +420,7 @@
   return -EFAULT;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_lseek
-*#                                                            
-*# PARAMETERS   : file     : Pointer to the file
-*#                offset   : The offset (in bytes)
-*#                orig     : look at the note
-*#                                                            
-*# RETURNS      : 0 if OK
-*#                                                            
-*# SIDE EFFECTS : 
-*#                                                            
-*# DESCRIPTION  : Changes the current file position.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version
-*# Sep 03 1999  Edgar Iglesias  Return -EOVERFLOW when beyond eeprom size.
-*#
-*#**************************************************************************/
+/* Changes the current file position. */
 
 static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
 {
@@ -549,29 +461,8 @@
   return ( file->f_pos );
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_read
-*#                                                            
-*# PARAMETERS   : inode    : Pointer to the inode
-*#                file     : Pointer to the file
-*#                buf      : Destination buffer
-*#                count    : max nr bytes to read
-*#                                                            
-*# RETURNS      : number of read bytes.
-*#                                                            
-*# SIDE EFFECTS : updates file->f_pos
-*#                                                            
-*# DESCRIPTION  : Reads data from eeprom.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Jan 17 2000  Johan Adolfsson Initial version
-*#
-*#**************************************************************************/
+/* Reads data from eeprom. */
+
 static int eeprom_read_buf(unsigned long addr,
                            char * buf, int count)
 {
@@ -583,31 +474,7 @@
 
 
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_read
-*#                                                            
-*# PARAMETERS   : file     : Pointer to the file
-*#                buf      : Destination buffer
-*#                count    : max nr bytes to read
-*#                                                            
-*# RETURNS      : number of read bytes.
-*#                                                            
-*# SIDE EFFECTS : updates file->f_pos
-*#                                                            
-*# DESCRIPTION  : Reads data from eeprom.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version               
-*# Aug 31 1999  Edgar Iglesias  Made operation atomic with wait queues
-*# Sep 03 1999  Edgar Iglesias  Added bail-out stuff if we get interrupted
-*#                              in the spin-lock.
-*#
-*#**************************************************************************/
+/* Reads data from eeprom. */
 
 static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off)
 {
@@ -636,8 +503,8 @@
   
   if(!eeprom_address(p))
   {
-    printk("eeprom: Read failed to address the eeprom: "
-           "0x%08X (%i) page: %i\n", p, p, page);
+    printk(KERN_INFO "%s: Read failed to address the eeprom: "
+           "0x%08X (%i) page: %i\n", eeprom_name, p, p, page);
     i2c_stop();
     
     /* don't forget to wake them up */
@@ -674,30 +541,9 @@
   return read;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_write_buf
-*#                                                            
-*# PARAMETERS   : addr     : Address to write to
-*#                buf      : Data buffer to write from
-*#                count    : number bytes to write
-*#                                                            
-*# RETURNS      : number of bytes actualy written.
-*#                                                            
-*# SIDE EFFECTS : None
-*#             
-*# DESCRIPTION  : Writes data to eeprom.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Jan 17 2000  Johan Adolfsson Initial vesion
-*#
-*#**************************************************************************/
-static int eeprom_write_buf(unsigned long int addr,
-                            const char * buf, int count)
+/* Writes data to eeprom. */
+
+static int eeprom_write_buf(unsigned long addr, const char * buf, int count)
 {
   struct file f;
 
@@ -707,33 +553,7 @@
 }
 
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_write
-*#                                                            
-*# PARAMETERS   : file     : Pointer to the file
-*#                buf      : Data buffer to write from
-*#                count    : number bytes to write
-*#                                                            
-*# RETURNS      : number of bytes actualy written.
-*#                                                            
-*# SIDE EFFECTS : updates file->f_pos
-*#             
-*# DESCRIPTION  : Writes data to eeprom.
-*#                                                            
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#                                                            
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version               
-*# Aug 31 1999  Edgar Iglesias  Made operation atomic with wait queues
-*# Sep 03 1999  Edgar Iglesias  Moved the actual reading to read_from_eeprom
-*# Sep 03 1999  Edgar Iglesias  Added bail-out stuff if we get interrupted
-*#                              in the spin-lock.
-*# May 18 2000  Edgar Iglesias  Make sure to end write cycle after every write.
-*#
-*#**************************************************************************/
+/* Writes data to eeprom. */
 
 static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
                             loff_t *off)
@@ -761,8 +581,8 @@
       /* address the eeprom */
       if(!eeprom_address(p))
       {
-        printk("eeprom: Write failed to address the eeprom: 0x%08X (%i) \n", 
-               p, p);
+        printk(KERN_INFO "%s: Write failed to address the eeprom: "
+               "0x%08X (%i) \n", eeprom_name, p, p);
         i2c_stop();
         
         /* don't forget to wake them up */
@@ -868,7 +688,7 @@
         if(!i2c_getack())
         {
           restart=1;
-          printk("eeprom: write error, retrying. %d\n", i);
+          printk(KERN_INFO "%s: write error, retrying. %d\n", eeprom_name, i);
           i2c_stop();
           break;
         }
@@ -891,28 +711,7 @@
   return written;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_close
-*#                                                            
-*# PARAMETERS   : inode    : Pointer to the inode
-*#                file     : Pointer to the file
-*#
-*# RETURNS      : nothing
-*#
-*# SIDE EFFECTS :
-*#
-*# DESCRIPTION  : Closes the device.
-*#
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version               
-*# Sep 03 1999  Edgar Iglesias  Removed eeprom.users stuff.
-*#
-*#**************************************************************************/
+/* Closes the device. */
 
 static int eeprom_close(struct inode * inode, struct file * file)
 {
@@ -920,27 +719,7 @@
   return 0;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_address
-*#                                                            
-*# PARAMETERS   : addr     : Address to be given to eeprom
-*#
-*# RETURNS      : 1 if OK, 0 if failure.
-*#
-*# SIDE EFFECTS :
-*#
-*# DESCRIPTION  : Sets the current address of the eeprom.
-*#
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Aug 28 1999  Edgar Iglesias  Initial version               
-*# Sep 03 1999  Edgar Iglesias  Corrected typo.
-*#
-*#**************************************************************************/
+/* Sets the current address of the eeprom. */
 
 static int eeprom_address(unsigned long addr)
 {
@@ -999,27 +778,7 @@
   return 1;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: read_from_eeprom
-*#                                                            
-*# PARAMETERS   : buf      : Destination buffer.
-*#                count    : Number of bytes to read.
-*#
-*# RETURNS      : number of read bytes or -EFAULT.
-*#
-*# SIDE EFFECTS :
-*#
-*# DESCRIPTION  : Reads from current adress.
-*#
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Sep 03 1999  Edgar Iglesias  Initial version               
-*#
-*#**************************************************************************/
+/* Reads from current adress. */
 
 static int read_from_eeprom(char * buf, int count)
 {
@@ -1040,7 +799,7 @@
   
   if(i == EEPROM_RETRIES)
   {
-    printk("eeprom: failed to read from eeprom\n");
+    printk(KERN_INFO "%s: failed to read from eeprom\n", eeprom_name);
     i2c_stop();
     
     return -EFAULT;
@@ -1066,26 +825,8 @@
   return read;
 }
 
-/*#**************************************************************************
-*#                                                            
-*# FUNCTION NAME: eeprom_disable_write_protect
-*#                                                            
-*# PARAMETERS   : None
-*#
-*# RETURNS      : Nothing
-*#
-*# SIDE EFFECTS :
-*#
-*# DESCRIPTION  : Disables write protection if applicable
-*#
-*#---------------------------------------------------------------------------
-*# HISTORY                                                    
-*#
-*# DATE         NAME            CHANGES                       
-*# ----         ----            -------                       
-*# Jan 14 2000  Johan Adolfsson Initial version (from PS pareerom.c)
-*#
-*#**************************************************************************/
+/* Disables write protection if applicable. */
+
 #define DBP_SAVE(x)
 #define ax_printf printk
 static void eeprom_disable_write_protect(void)
@@ -1133,7 +874,7 @@
     }
     i2c_stop();
     
-    /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh*/
+    /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh */
     i2c_start();
     i2c_outbyte(0xbe);
     if(!i2c_getack())
@@ -1157,5 +898,3 @@
 }
 
 module_init(eeprom_init);
-
-/********************** END OF FILE e100eeprom.c *****************************/
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c
--- v2.4.6/linux/arch/cris/drivers/ethernet.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/ethernet.c	Wed Jul  4 11:50:38 2001
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $
+/* $Id: ethernet.c,v 1.17 2001/06/11 12:43:46 olof Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,23 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.17  2001/06/11 12:43:46  olof
+ * Modified defines for network LED behavior
+ *
+ * Revision 1.16  2001/05/30 06:12:46  markusl
+ * TxDesc.next should not be set to NULL
+ *
+ * Revision 1.15  2001/05/29 10:27:04  markusl
+ * Updated after review remarks:
+ * +Use IO_EXTRACT
+ * +Handle underrun
+ *
+ * Revision 1.14  2001/05/29 09:20:14  jonashg
+ * Use driver name on printk output so one can tell which driver that complains.
+ *
+ * Revision 1.13  2001/05/09 12:35:59  johana
+ * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
+ *
  * Revision 1.12  2001/04/05 11:43:11  tobiasa
  * Check dev before panic.
  *
@@ -80,6 +97,7 @@
 
 #include <asm/svinto.h>     /* DMA and register descriptions */
 #include <asm/io.h>         /* LED_* I/O functions */
+#include <asm/irq.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -87,8 +105,6 @@
 //#define ETHDEBUG
 #define D(x)
 
-#define ETH_TX_DMA 0
-#define ETH_RX_DMA 1
 
 /*
  * The name of the card. Is used for messages and in the requests for
@@ -116,9 +132,6 @@
 	spinlock_t lock;
 };
 
-#define NETWORK_DMARX_IRQ 17  /* irq 17 is the DMA1 irq */
-#define NETWORK_DMATX_IRQ 16  /* irq 16 is the DMA0 irq */
-#define NETWORK_STATUS_IRQ 6  /* irq 6 is the network irq */
 
 /* Dma descriptors etc. */
 
@@ -231,7 +244,8 @@
 	/* make Linux aware of the new hardware  */
 
 	if (!dev) {
-		printk("dev == NULL. Should this happen?\n");
+		printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n",
+		       cardname);
 		dev = init_etherdev(dev, sizeof(struct net_local));
 		if (!dev)
 			panic("init_etherdev failed\n");
@@ -250,8 +264,8 @@
 
 	/* now setup our etrax specific stuff */
 
-	dev->irq = NETWORK_DMARX_IRQ; /* we really use DMATX as well... */
-	dev->dma = 1;
+	dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */
+	dev->dma = NETWORK_RX_DMA_NBR;
 
 	/* fill in our handlers so the network layer can talk to us in the future */
 
@@ -381,30 +395,30 @@
 
 	/* Reset and wait for the DMA channels */
 
-	RESET_DMA(0);
-	RESET_DMA(1);
-	WAIT_DMA(0);
-	WAIT_DMA(1);
+	RESET_DMA(NETWORK_TX_DMA_NBR);
+	RESET_DMA(NETWORK_RX_DMA_NBR);
+	WAIT_DMA(NETWORK_TX_DMA_NBR);
+	WAIT_DMA(NETWORK_RX_DMA_NBR);
 
 	/* Initialise the etrax network controller */
 
 	/* allocate the irq corresponding to the receiving DMA */
 
-	if (request_irq(NETWORK_DMARX_IRQ, e100rx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit;
 	}
 
 	/* allocate the irq corresponding to the transmitting DMA */
 
-	if (request_irq(NETWORK_DMATX_IRQ, e100tx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit;
 	}
 
 	/* allocate the irq corresponding to the network errors etc */
 
-	if (request_irq(NETWORK_STATUS_IRQ, e100nw_interrupt, 0,
+	if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit;
 	}
@@ -414,17 +428,17 @@
 	 * and clean up on failure.
 	 */
 
-	if(request_dma(ETH_TX_DMA, cardname)) {
+	if(request_dma(NETWORK_TX_DMA_NBR, cardname)) {
 		goto grace_exit;
 	}
 
-	if(request_dma(ETH_RX_DMA, cardname)) {
+	if(request_dma(NETWORK_RX_DMA_NBR, cardname)) {
 	grace_exit:
 		/* this will cause some 'trying to free free irq' but what the heck... */
-		free_dma(ETH_TX_DMA);
-		free_irq(NETWORK_DMARX_IRQ, (void *)dev);
-		free_irq(NETWORK_DMATX_IRQ, (void *)dev);
-		free_irq(NETWORK_STATUS_IRQ, (void *)dev);
+		free_dma(NETWORK_TX_DMA_NBR);
+		free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+		free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+		free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
 		return -EAGAIN;
 	}
 
@@ -625,8 +639,8 @@
 	
 	/* reset the TX DMA in case it has hung on something */
 	
-	RESET_DMA(0);
-	WAIT_DMA(0);
+	RESET_DMA(NETWORK_TX_DMA_NBR);
+	WAIT_DMA(NETWORK_TX_DMA_NBR);
 	
 	/* Reset the tranceiver. */
 	
@@ -751,7 +765,8 @@
 			tx_skb = 0;
 			netif_wake_queue(dev);
 		} else {
-			printk("tx weird interrupt\n");
+			printk(KERN_WARNING "%s: tx weird interrupt\n",
+			       cardname);
 		}
 
 		spin_unlock(&np->lock);
@@ -765,6 +780,13 @@
 	struct net_local *np = (struct net_local *)dev->priv;
 	unsigned long irqbits = *R_IRQ_MASK0_RD;
 
+	/* check for underrun irq */
+	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { 
+		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
+		np->stats.tx_errors++;
+		D(printk("ethernet receiver underrun!\n"));
+	}
+
 	/* check for overrun irq */
 	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { 
 		update_rx_stats(&np->stats); /* this will ack the irq */
@@ -900,17 +922,17 @@
 
 	/* Stop the receiver and the transmitter */
 
-	RESET_DMA(0);
-	RESET_DMA(1);
+	RESET_DMA(NETWORK_TX_DMA_NBR);
+	RESET_DMA(NETWORK_RX_DMA_NBR);
 
 	/* Flush the Tx and disable Rx here. */
 
-	free_irq(NETWORK_DMARX_IRQ, (void *)dev);
-	free_irq(NETWORK_DMATX_IRQ, (void *)dev);
-	free_irq(NETWORK_STATUS_IRQ, (void *)dev);
+	free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
 
-	free_dma(ETH_TX_DMA);
-	free_dma(ETH_RX_DMA);
+	free_dma(NETWORK_TX_DMA_NBR);
+	free_dma(NETWORK_RX_DMA_NBR);
 
 	/* Update the statistics here. */
 
@@ -925,10 +947,10 @@
 {
 	unsigned long r = *R_REC_COUNTERS;
 	/* update stats relevant to reception errors */
-	es->rx_fifo_errors += r >> 24;            /* fifo overrun */
-	es->rx_crc_errors += r & 0xff;            /* crc error */
-	es->rx_frame_errors += (r >> 8) & 0xff;   /* alignment error */
-	es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */
+	es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r);
+	es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r);
+	es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r);
+	es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r);
 }
 
 static void
@@ -936,8 +958,10 @@
 {
 	unsigned long r = *R_TR_COUNTERS;
 	/* update stats relevant to transmission errors */
-	es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */
-	es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */
+	es->collisions +=
+		IO_EXTRACT(R_TR_COUNTERS, single_col, r) +
+		IO_EXTRACT(R_TR_COUNTERS, multiple_col, r);
+	es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);
 }
 
 /*
@@ -1082,10 +1106,12 @@
 static void
 e100_set_network_leds(int active)
 {
-#ifdef CONFIG_LED_OFF_DURING_ACTIVITY
+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
 	int light_leds = (active == NO_NETWORK_ACTIVITY);
-#else
+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
 	int light_leds = (active == NETWORK_ACTIVITY);
+#else
+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
 #endif
 
 	if (!current_speed) {
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c
--- v2.4.6/linux/arch/cris/drivers/gpio.c	Sat May 19 17:43:05 2001
+++ linux/arch/cris/drivers/gpio.c	Wed Jul  4 11:50:38 2001
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.7 2001/04/04 13:30:08 matsfg Exp $
+/* $Id: gpio.c,v 1.9 2001/05/04 14:16:07 matsfg Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,14 @@
  *             Johan Adolfsson  (read/set directions)
  *
  * $Log: gpio.c,v $
+ * Revision 1.9  2001/05/04 14:16:07  matsfg
+ * Corrected spelling error
+ *
+ * Revision 1.8  2001/04/27 13:55:26  matsfg
+ * Moved initioremap.
+ * Turns off all LEDS on init.
+ * Added support for shutdown and powerbutton.
+ *
  * Revision 1.7  2001/04/04 13:30:08  matsfg
  * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
  *
@@ -247,6 +255,16 @@
 			*priv->dir = *priv->dir_shadow |= 
 			  ((unsigned char)arg & priv->changeable_dir);
 			return *priv->dir_shadow;
+                case IO_SHUTDOWN:
+                       SOFT_SHUTDOWN();
+                       break;
+                case IO_GET_PWR_BT:
+#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
+                       return (*R_PORT_G_DATA & 
+                               ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
+#else
+                       return 0;
+#endif
 		default:
 			if(priv->minor == LEDS)
 				return gpio_leds_ioctl(cmd, arg);
@@ -262,12 +280,6 @@
 {
 	unsigned char green;
 	unsigned char red;
-        static int initialized = 0;
-        if(!initialized)
-        {
-          initialized = 1;
-          init_ioremap();
-        }
 	switch (_IOC_NR(cmd)) {
 		case IO_LEDACTIVE_SET:
 			green = ((unsigned char) arg) & 1;
@@ -298,7 +310,7 @@
 static __init int
 gpio_init(void)
 {
-	int res;
+	int res,i;
 
 	/* do the formalities */
 
@@ -307,6 +319,24 @@
 		printk(KERN_ERR "gpio: couldn't get a major number.\n");
 		return res;
 	}
+
+        /* Clear all leds */
+#if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS)         || defined (CONFIG_ETRAX_PB_LEDS) 
+
+        init_ioremap();
+        LED_NETWORK_SET(0);
+        LED_ACTIVE_SET(0);
+        LED_DISK_READ(0);
+        LED_DISK_WRITE(0);        
+
+#if defined (CONFIG_ETRAX_CSP0_LEDS)
+        for( i = 0; i < 32; i ++)
+        {
+            LED_BIT_SET(i);
+        }
+#endif
+
+#endif
 	
 	printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n");
 
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- v2.4.6/linux/arch/cris/drivers/ide.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/cris/drivers/ide.c	Wed Jul  4 11:50:38 2001
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.16 2001/04/05 08:30:07 matsfg Exp $
+/* $Id: ide.c,v 1.19 2001/05/09 12:53:16 johana Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,15 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.19  2001/05/09 12:53:16  johana
+ * Added #include <asm/dma.h>
+ *
+ * Revision 1.18  2001/05/09 12:37:00  johana
+ * Use DMA_NBR macros from dma.h.
+ *
+ * Revision 1.17  2001/04/23 13:36:30  matsfg
+ * Changed CONFIG_IDE_DELAY to CONFIG_ETRAX_IDE_DELAY
+ *
  * Revision 1.16  2001/04/05 08:30:07  matsfg
  * Corrected cse1 and csp0 reset.
  *
@@ -98,6 +107,7 @@
 
 #include <asm/io.h>
 #include <asm/svinto.h>
+#include <asm/dma.h>
 
 /* number of Etrax DMA descriptors */
 #define MAX_DMA_DESCRS 64
@@ -341,17 +351,17 @@
 			     IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
 			     IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
 
-	printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_IDE_DELAY);
+	printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY);
 
-	h = jiffies + (CONFIG_IDE_DELAY * HZ);
+	h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
 	while(jiffies < h) ;
 
   /* reset the dma channels we will use */
 
-	RESET_DMA(2);
-	RESET_DMA(3);
-	WAIT_DMA(2);
-	WAIT_DMA(3);
+	RESET_DMA(ATA_TX_DMA_NBR);
+	RESET_DMA(ATA_RX_DMA_NBR);
+	WAIT_DMA(ATA_TX_DMA_NBR);
+	WAIT_DMA(ATA_RX_DMA_NBR);
 
 }
 
@@ -378,8 +388,8 @@
 	}
 	
 	/* make sure the DMA channel is available */
-	RESET_DMA(3);
-	WAIT_DMA(3); 
+	RESET_DMA(ATA_RX_DMA_NBR);
+	WAIT_DMA(ATA_RX_DMA_NBR); 
 	
 	/* setup DMA descriptor */
 	
@@ -406,7 +416,7 @@
 	/* wait for completion */
 	
 	LED_DISK_READ(1);
-	WAIT_DMA(3);
+	WAIT_DMA(ATA_RX_DMA_NBR);
 	LED_DISK_READ(0);
 
 #if 0
@@ -457,8 +467,8 @@
 	}
 
 	/* make sure the DMA channel is available */
-	RESET_DMA(2);
-	WAIT_DMA(2); 
+	RESET_DMA(ATA_TX_DMA_NBR);
+	WAIT_DMA(ATA_TX_DMA_NBR); 
 	
 	/* setup DMA descriptor */
 	
@@ -485,7 +495,7 @@
 	/* wait for completion */
 	
 	LED_DISK_WRITE(1);
-	WAIT_DMA(2);
+	WAIT_DMA(ATA_TX_DMA_NBR);
 	LED_DISK_WRITE(0);
 
 #if 0
@@ -794,8 +804,8 @@
 
 	if(reading) {
 
-		RESET_DMA(3); /* sometimes the DMA channel get stuck so we need to do this */
-		WAIT_DMA(3);
+		RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+		WAIT_DMA(ATA_RX_DMA_NBR);
 
 		/* set up the Etrax DMA descriptors */
 		
@@ -837,8 +847,8 @@
 	} else {
 		/* writing */
 
-		RESET_DMA(2); /* sometimes the DMA channel get stuck so we need to do this */
-		WAIT_DMA(2);
+		RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+		WAIT_DMA(ATA_TX_DMA_NBR);
 
 		/* set up the Etrax DMA descriptors */
 
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/Makefile linux/arch/cris/drivers/lpslave/Makefile
--- v2.4.6/linux/arch/cris/drivers/lpslave/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/Makefile	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,20 @@
+#
+# Makefile for parallel port slave drivers
+#
+
+O_TARGET := lpslavedrivers.o
+
+obj-y = e100lpslavenet.o e100lpslave_code.o
+
+
+include $(TOPDIR)/Rules.make
+
+e100lpslave_code.o:	e100lpslave.o e100lpslaveld 
+	$(CROSS_COMPILE)ld -qmagic -Te100lpslaveld e100lpslave.o -o e100lpslave
+	$(CROSS_COMPILE)objcopy -O binary --remove-section=.data --remove-section=.bss e100lpslave e100lpslave.text
+	$(CROSS_COMPILE)objcopy -O binary --remove-section=.text --remove-section=.bss e100lpslave e100lpslave.data
+	cat e100lpslave.text e100lpslave.data |\
+	./bintocarr.pl e100lpslaveprog |\
+	$(CC) $(CFLAGS) -pipe -o e100lpslave_code.o -c -x c -
+	ls -l e100lpslave.text e100lpslave.data
+	rm -f e100lpslave e100lpslave.text e100lpslave.data
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/bintocarr.pl linux/arch/cris/drivers/lpslave/bintocarr.pl
--- v2.4.6/linux/arch/cris/drivers/lpslave/bintocarr.pl	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/bintocarr.pl	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,29 @@
+#!/usr/bin/perl -w
+# $Id: bintocarr.pl,v 1.3 2001/06/08 08:46:50 olof Exp $
+# Copy of mkjulbin.pl made by Olof
+# convert a binary stdin to a C-file containing a char array of the input
+# first argument is the symbol name
+
+$symbol = shift @ARGV;
+
+print "#include <linux/init.h>\n\n";
+print "unsigned char $symbol", "[] __initdata = {\n";
+
+my $char;
+
+$bcount = 0;
+
+while(read STDIN, $char, 1) {
+    printf("0x%x, ", ord($char));
+    $bcount++;
+    if(!($bcount % 16)) {
+	print "\n";
+    }
+}
+
+print "\n};\n";
+
+$lensymb = ("_" . ($symbol . "_length"));
+
+print "__asm__(\"\\t.globl $lensymb\\n$lensymb = $bcount\\n\");\n";
+  
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.README linux/arch/cris/drivers/lpslave/e100lpslave.README
--- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.README	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/e100lpslave.README	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,54 @@
+***** MODIFICATIONS
+To use a 5600 as a slave device it has to somewhat modified.
+This has to be done on a 5600 (art no 16144 R2) to automatically set it to parallel port boot mode:
+
+1)
+Close to the LPT1 connector there are two resistors, between the "Pulse" inductor and
+the LS245. The one closest to the LS245 is a 4k7 pull up (R105). Remove it.
+
+2)
+Between the other "Pulse" inductor and Etrax there is a black 5-pin inverter
+(D15). Short connectors 2 and 3 with a solder blob.
+
+
+***** PINOUT
+To use this driver use cables connected like this:
+DSUB25-Male                DSUB25Male
+
+1	10
+2-9	2-9
+10 	1
+11	14
+12	18
+13	NC
+14	11
+15	NC
+16	NC	
+17	NC
+18	12
+19	NC
+20-25	20-25
+
+Thus the cables are symmetrical with most cables straight through,
+some crossed (1-10, 11-14 and 12-18) 
+and some Not connected (NC 13,15,16,17 and 19).
+
+
+******* Only for reference
+To ease the use of flat-cable connectors, here are the notes of wich wires to cross and cut with pin 1 being cable 1:
+Cross:
+1	19
+2	21
+10	23
+Cut:
+4
+6
+8
+12
+25
+
+jonas.dellenvall@axis.com
+
+
+
+
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.S linux/arch/cris/drivers/lpslave/e100lpslave.S
--- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/e100lpslave.S	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,429 @@
+	;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $
+	;;
+	;; Etrax100 slave network<->parport forwarder
+	;;
+	;; Copyright (c) 1999 Bjorn Wesen, Axis Communications AB
+	;;
+	;; We got 784 bytes (par loader size) to do DMA forwarding
+	;; between DMA0/1 (ethernet) and DMA3/4 (par port 0 RX/1 TX)
+	;;
+
+#include <linux/config.h>
+#if 0
+#define ASSEMBLER_MACROS_ONLY
+#endif
+#include <asm/sv_addr_ag.h>
+
+#define BUFSIZE 0x600
+
+	;; R_IRQ_READ2
+
+#define DMA1EOPBIT 3
+#define DMA0EOPBIT 1
+#define DMA3EOPBIT 7
+#define DMA4DESCBIT 8
+
+	;; R_IRQ_READ0
+
+#define PAR0ECPCMDBIT 11
+
+	;; get host CMDs
+
+#include "e100lpslave.h"
+
+start:
+	;; disable interrupts. we are not going to use them at all.
+
+	di
+
+	;; setup DMA connections and port configuration
+
+	movu.w	0x84, r0	; DMA2/3/4/5 to par ports
+	move.d	r0, [R_GEN_CONFIG]
+
+	;; setup port PA dirs and turn on the LED to show were alive
+
+	movu.w	0x0cfb, r0	; PA2-PA3 out, PA2 inactive
+	move.d	r0, [R_PORT_PA_SET]
+
+	;; enable MDIO output pin
+	moveq IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable), r0
+	move.d	r0, [R_NETWORK_MGM_CTRL]
+
+	;; accept broadcast frames, and enable station address 0
+	moveq	IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | \
+		IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable), r0
+	move.d	r0, [R_NETWORK_REC_CONFIG]
+
+	;; use MII CLK mode, and enable the controller
+	moveq	IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | \
+		IO_STATE(R_NETWORK_GEN_CONFIG, enable, on), r0
+	move.d	r0, [R_NETWORK_GEN_CONFIG]
+
+	move.d	IO_STATE(R_PAR0_CONFIG, ioe,     noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, iseli,   noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, iautofd, noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, istrb,   noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, iinit,   noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, iperr,   noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, iack,    noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, ibusy,   noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, ifault,  noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, isel,    noninv)    |  \
+		IO_STATE(R_PAR0_CONFIG, dma, enable)        |  \
+		IO_STATE(R_PAR0_CONFIG, rle_in, disable)    |  \
+		IO_STATE(R_PAR0_CONFIG, rle_out, disable)   |  \
+		IO_STATE(R_PAR0_CONFIG, enable, on)         |  \
+		IO_STATE(R_PAR0_CONFIG, force, on)          |  \
+		IO_STATE(R_PAR0_CONFIG, mode, ecp_rev), r0	; Reverse ECP - PAR0 is RX
+
+	move.d	r0, [R_PAR0_CONFIG]
+
+	move.d	IO_STATE(R_PAR1_CONFIG, ioe,     noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, iseli,   noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, iautofd, noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, istrb,   noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, iinit,   noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, iperr,   inv)       |  \
+		IO_STATE(R_PAR1_CONFIG, iack,    noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, ibusy,   noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, ifault,  noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, isel,    noninv)    |  \
+		IO_STATE(R_PAR1_CONFIG, dma, enable)        |  \
+		IO_STATE(R_PAR1_CONFIG, rle_in, disable)    |  \
+		IO_STATE(R_PAR1_CONFIG, rle_out, disable)   |  \
+		IO_STATE(R_PAR1_CONFIG, enable, on)         |  \
+		IO_STATE(R_PAR1_CONFIG, force, on)          |  \
+		IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd), r0	; Forward ECP - PAR1 is TX
+
+	move.d	r0, [R_PAR1_CONFIG]
+
+	moveq	IO_FIELD(R_PAR1_DELAY, setup, 1), r0    ; setup time of value * 160 + 20
+	move.d	r0, [R_PAR1_DELAY]
+
+	;; we got four descriptors, that can be active at the same time:
+	;; 1) from network
+	;; 2) to parport
+	;; 3) from parport
+	;; 4) to network
+	;;
+	;; we got four buffers, each can hold a max packet (we use 1536 bytes)
+	;; buffers 1 and 2 are used from network to parport, while
+	;; buffers 3 and 4 are used from parport to network.
+	;; 
+	;; a double buffering scheme is used, so that new data can be read
+	;; into a buffer pair while the last data is written out from the
+	;; last buffer. if the read buffer is done before the write buffer,
+	;; the reading will halt until the writing is done, at which point
+	;; writing starts from the newly read and reading can start with
+	;; the newly written.
+	;; 
+
+	move.d	R_DMA_CH0_FIRST, r1   ; we use this as base for subsequent DMA ops
+	moveq	IO_STATE(R_DMA_CH1_CMD, cmd, start), r6
+	move.d	FN1desc, r7
+	move.d	R_IRQ_READ0, r9
+
+	;; start receiving from network
+
+	jsr	startdmaFPTN
+	jsr	startdmaFNTP
+
+	
+
+	;; ------------------- MAIN LOOP
+
+	;; IRQ bits:	parport rcv is par0_ecp_cmd, then dma3_eop
+	;;              network rcv is dma1_eop
+	;;              parport tx  is dma4_desc
+	;;              network tx  is dma0_eop
+
+mainloop:
+
+	;; ------- first handle the parport -> network link
+
+	;; check if we got something from the parport
+
+	move.d	[r9], r0	; r0 <- *R_IRQ_READ0
+	btstq	PAR0ECPCMDBIT, r0
+	bpl	noparecp
+	nop
+
+	;; ack it by reading PAR0_STATUS_DATA
+
+	move.d	[R_PAR0_STATUS_DATA], r0
+
+	;; trigger EOP on DMA3 (par0 incoming channel)
+
+	moveq	IO_STATE(R_SET_EOP, ch3_eop, set), r0
+	move.d	r0, [R_SET_EOP]
+
+noparecp:
+
+	;; if we simultaneously have parport rx EOP and
+	;; network TX eop, we can swap buffers and start a new RX/TX
+
+	move.d	[r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0
+	btstq	DMA3EOPBIT, r0	; check parport rx
+	bpl	noswap1
+	btstq	DMA0EOPBIT, r0	; check network tx
+	bpl	noswap1
+	nop
+
+	;; prepare to swap buffer ptrs (FN3b <-> TN4b)
+
+	move.d	[r4 = r7 + 56], r0; FP3b
+	move.d	[r3 = r7 + 72], r2; TN4b
+
+	;; but first check if this was a Host Command Packet
+
+	move.d	[r0], r5	; r5 <- first 4 bytes in PAR-received packet
+	bne	handle_command	; if non-zero, it was a host command
+	addq	4, r0		; skip command (in delay slot - handle_command requires this)
+	move.d	r0, [r3]	; write to To Network descriptor
+	subq	4, r2		; undo the skipping done last swap
+	move.d	r2, [r4]	; write to From Parport descriptor
+
+	;; clear the interrupts
+
+	moveq	IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do), r0
+	move.b	r0, [r1 + (R_DMA_CH0_CLR_INTR - R_DMA_CH0_FIRST)]
+	move.b	r0, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)]
+
+	;; copy received length to outgoing network length
+
+	move.w	[r7 + 60], r0	; FPhlen
+	subq	4, r0		; skip command
+	move.w	r0, [r7 + 64]	; TN4desc
+
+	;; restart DMAs
+
+	jsr	startdmaFPTN
+
+#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
+	;; Turn off the LED signaling an outgoing network packet
+	movu.b	[LEDOff], r0
+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
+	;; Light the LED signaling an outgoing network packet
+	movu.b	[LEDAmber], r0
+#else
+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"	
+#endif 
+	move.b	r0, [R_PORT_PA_DATA]
+	move.d	0x00011000, r0
+	move.d	r0,[LEDCount]
+#endif
+
+noswap1:
+	;; ----- now check the network -> parport link
+
+
+	;; if we simultaneously have network rx EOP and
+	;; parport TX desc, we can swap buffers and start a new RX/TX
+
+	move.d	[r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0
+	btstq	DMA1EOPBIT, r0	; check network rx
+	bpl	noswap2
+	btstq	DMA4DESCBIT, r0	; check parport tx
+	bpl	noswap2
+	nop
+
+	;; prepare to swap buffer ptrs (FP1b <-> TP2b)
+
+	move.d	[r4 = r7 +  8], r0; FN1b
+	move.d	[r3 = r7 + 24], r2; TP2b
+	move.d	r0, [r3]	; write to To Parport descriptor
+	move.d	r2, [r4]	; write to From Network descriptor
+
+	;; clear the interrupts
+
+	moveq	IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | \
+		IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do), r0
+	move.b	r0, [r1 + (R_DMA_CH1_CLR_INTR - R_DMA_CH0_FIRST)]
+	move.b	r0, [r1 + (R_DMA_CH4_CLR_INTR - R_DMA_CH0_FIRST)]
+
+	;; copy received network length to outgoing parport length
+
+	move.w	[r7 + 12], r0	; FNhlen
+	move.w	r0, [r7 + 16]	; TP2desc
+
+	;; restart DMAs
+
+	jsr	startdmaFNTP
+#if 0
+#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
+	;; Light the LED signaling an incoming networkpacket
+	movu.b	0xFB, r0
+	move.b	r0, [R_PORT_PA_DATA]
+	move.d	0x00010000, r0
+	move.d	r0,[LEDCount]
+#endif
+#endif
+
+noswap2:
+#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
+
+	;; Count down LED counter, and turn off the network LED if required
+	move.d	[LEDCount], r0
+	beq	mainloop
+	nop
+
+	subq	1, r0
+	move.d	r0, [LEDCount]	
+	bne	mainloop
+	nop
+
+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)	
+	;; Light the network LED , and start over the main loop
+	movu.b	[LEDAmber], r0
+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)		
+	;; Turn off the network LED, and start over the main loop
+	movu.b	[LEDOff], r0
+#else
+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"	
+#endif
+	move.b	r0, [R_PORT_PA_DATA]
+#endif
+
+	ba	mainloop
+	nop
+
+	;; --- some useful subroutines.
+
+handle_command:
+	;; handle command. we also need to clear the PAR0 RX EOP IRQ, and 
+	;; restart the PAR0 dma. command is in R5, packet after cmd is in R0
+
+	moveq	IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do), r2
+	move.b	r2, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)]
+
+	cmpq	HOST_CMD_SETMAC, r5
+	bne	no_setmac
+	nop
+
+	;; copy station address (6 bytes) from packet to hardware
+
+	move.d	[r0+], r2
+	move.d	R_NETWORK_SA_0, r3
+	move.d	r2, [r3]
+	move.w	[r0], r2
+	move.w	r2, [r3 + 4] 
+
+no_setmac:
+	move	noswap1, SRP
+	ba	startdmaFP
+	nop
+
+	;; start DMAs, from parport and to network
+
+startdmaFPTN:
+
+	;; start transmitting to the network (CH0)
+
+	move.d	TN4desc, r8
+	move.d	r8, [r1]					; TN4desc -> FIRST0
+	move.b	r6, [r1 + (R_DMA_CH0_CMD - R_DMA_CH0_FIRST)]	; start -> CMD0
+
+startdmaFP:
+
+	;; start receiving from parport (CH3)
+
+	move.d	FP3desc, r8
+	move.d	r8, [r1 + (R_DMA_CH3_FIRST - R_DMA_CH0_FIRST)]  ; FP3desc -> FIRST3
+	move.b	r6, [r1 + (R_DMA_CH3_CMD - R_DMA_CH0_FIRST)]	; start -> CMD3
+
+	ret
+	nop
+
+	;; start DMAs, from network and to parport
+
+startdmaFNTP:
+
+	;; start transmitting to the parport (CH4)
+
+	move.d	TP2desc, r8
+	move.d	r8, [r1 + (R_DMA_CH4_FIRST - R_DMA_CH0_FIRST)]	; TP2desc -> FIRST4
+	move.b	r6, [r1 + (R_DMA_CH4_CMD - R_DMA_CH0_FIRST)]	; start -> CMD4
+
+	;; start receiving from network (CH1) (r7 already contains FN1desc)
+
+	move.d	r7, [r1 + (R_DMA_CH1_FIRST - R_DMA_CH0_FIRST)]  ; FN1desc -> FIRST1
+	move.b	r6, [r1 + (R_DMA_CH1_CMD - R_DMA_CH0_FIRST)]	; start -> CMD1
+
+	ret
+	nop
+
+	;; --- DMA descriptors - each descriptor is 4 longwords (16 bytes)
+	;; DONT MOVE THESE AROUND. Due to the as/ld "hole-in-the-head",
+	;; we cant write stuff like (TP2b - TP2desc) but the offsets
+	;; have to be hardcoded.
+
+	.data
+
+	;; 0 from network
+FN1desc:
+	.word	BUFSIZE		; sw_len
+	.word	0x0001		; ctrl, d_eol is only flag we need
+	.dword	0		; next
+FN1b:	.dword	buffers		; buffer 1 8
+	.word	0		; hw_len
+	.word	0		; status
+
+	;; 16 to parport
+TP2desc:
+	.word	2		; sw_len, filled in by code 
+	.word	0x0004		; ctrl, d_wait because ecp cmd in next
+	.dword	TP2desc2	; next
+TP2b:	.dword	buffers + BUFSIZE ; buffer 2 24
+	.word	0		; hw_len
+	.word	0		; status
+
+	;; 32 to parport second descriptor, for the ECP command
+TP2desc2:
+	.word	0x0001		; sw_len, 1 byte (ecp command) 
+	.word	0x0019		; ctrl, d_ecp | d_eol | d_int
+	.dword	0		; next
+	.dword	TP2desc2	; buffer, dont care
+	.word	0		; hw_len
+	.word	0		; status
+
+	;; 48 from parport
+FP3desc:
+	.word	BUFSIZE		; sw_len
+	.word	0x0001		; ctrl, d_eol is only flag we need
+	.dword	0		; next
+FP3b:	.dword	buffers + BUFSIZE * 2 ; 56 buffer 3
+FPhlen:	.word	0		; 60 hw_len
+	.word	0		; status
+
+	;; 64 to network
+TN4desc:
+	.word	2		; sw_len, filled in by code 
+	.word	0x0007		; ctrl, d_eop | d_eol | d_wait
+	.dword	0		; next
+TN4b:	.dword	buffers + BUFSIZE * 3 + 4	; 72 buffer 4 (the +4 is to offset the anti-skipping)
+	.word	0		; hw_len
+	.word	0		; status
+
+#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
+LEDCount:
+	.dword	0
+LEDOff:	
+	.word	0xff
+LEDGreen:
+	.word	0xfb
+LEDRed:
+	.word	0xf7
+LEDAmber:
+	.word	0xf3
+LED:
+	.word	0xf7
+#endif
+
+	;; after the prog we put the buffers. not in the asm program, we just use
+	;; the address generated
+
+buffers:
+
+	;; END
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.h linux/arch/cris/drivers/lpslave/e100lpslave.h
--- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/e100lpslave.h	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,2 @@
+#define HOST_CMD_SENDPACK 0
+#define HOST_CMD_SETMAC 1
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslaveld linux/arch/cris/drivers/lpslave/e100lpslaveld
--- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslaveld	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/e100lpslaveld	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,22 @@
+MEMORY 
+	{
+	cache : ORIGIN = 0x380000f0,
+	       	LENGTH = 784
+	}
+
+SECTIONS
+{
+	.text :
+	{
+		*(.text)
+	} > cache
+	.data :
+	{
+		*(.data)
+		*(COMMON)
+	} > cache
+	.bss :
+	{
+		*(.bss)
+	} > cache
+}
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslavenet.c linux/arch/cris/drivers/lpslave/e100lpslavenet.c
--- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslavenet.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/lpslave/e100lpslavenet.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,1031 @@
+/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $
+ *
+ * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller.
+ *
+ * Copyright (c) 1998-2001 Axis Communications AB.
+ *
+ * The outline of this driver comes from skeleton.c.
+ *
+ * $Log: e100lpslavenet.c,v $
+ * Revision 1.2  2001/06/11 15:39:52  olof
+ * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave.
+ *
+ * Revision 1.1  2001/06/06 08:56:26  olof
+ * Added support for slave Etrax defined by CONFIG_ETRAX_ETHERNET_LPSLAVE
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/svinto.h>     /* DMA and register descriptions */
+#include <asm/io.h>         /* LED_* I/O functions */
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include "e100lpslave.h"
+
+/* #define ETHDEBUG */
+#define D(x)
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+
+static const char* cardname = "Etrax 100LX ethernet slave controller";
+
+/* A default ethernet address. Highlevel SW will set the real one later */
+
+static struct sockaddr default_mac = {
+	0,
+        { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
+};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct net_device_stats stats;
+
+	/* Tx control lock.  This protects the transmit buffer ring
+	 * state along with the "tx full" state of the driver.  This
+	 * means all netif_queue flow control actions are protected
+	 * by this lock as well.
+	 */
+	spinlock_t lock;
+};
+
+/* Dma descriptors etc. */
+
+#define RX_BUF_SIZE 32768
+#define ETHER_HEAD_LEN      14
+
+#define PAR0_ECP_IRQ_NBR    4
+
+#define RX_DESC_BUF_SIZE   256
+#define NBR_OF_RX_DESC     (RX_BUF_SIZE / \
+			    RX_DESC_BUF_SIZE)
+
+/* Size of slave etrax boot image */
+#define ETRAX_PAR_BOOT_LENGTH 784
+
+static etrax_dma_descr *myNextRxDesc;  /* Points to the next descriptor to
+					  to be processed */
+static etrax_dma_descr *myLastRxDesc;  /* The last processed descriptor */
+static etrax_dma_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
+
+static unsigned char RxBuf[RX_BUF_SIZE];
+
+static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4)));
+static etrax_dma_descr TxDescList[3] __attribute__ ((aligned(4)));
+                       /* host command, data, bogus ECP command */
+
+static struct sk_buff *tx_skb;
+
+/* Index to functions, as function prototypes. */
+
+static int etrax_ethernet_lpslave_init(struct net_device *dev);
+
+static int e100_open(struct net_device *dev);
+static int e100_set_mac_address(struct net_device *dev, void *addr);
+static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void ecp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100_rx(struct net_device *dev);
+static int e100_close(struct net_device *dev);
+static struct net_device_stats *e100_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length);
+static void update_rx_stats(struct net_device_stats *);
+static void update_tx_stats(struct net_device_stats *);
+static void e100_reset_tranceiver(void);
+
+static void boot_slave(unsigned char *code);
+
+#ifdef ETHDEBUG
+static void dump_parport_status(void);
+#endif
+
+#define tx_done(dev) (*R_DMA_CH0_CMD == 0)
+
+static unsigned long host_command;
+extern unsigned char e100lpslaveprog;
+
+/*
+ * This driver uses PAR0 to recevice data from slave ETRAX and PAR1 to boot
+ * and send data to slave ETRAX.
+ * Used ETRAX100 DMAchannels with corresponding IRQ:
+ * PAR0 RX : DMA3 - IRQ 19
+ * PAR1 TX : DMA4 - IRQ 20
+ * IRQ 4 is used to detect ECP commands from slave ETRAX
+ *
+ * NOTE! PAR0 and PAR1 shares DMA and IRQ numbers with SER2 and SER3 
+ */
+
+
+/*
+ * Check for a network adaptor of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, allocate space for the device and return success
+ * (detachable devices only).
+ */
+static int __init
+etrax_ethernet_lpslave_init(struct net_device *dev)
+{
+	int i;
+	int anOffset = 0;
+
+	printk("Etrax/100 lpslave ethernet driver v0.3, (c) 1999 Axis Communications AB\n");
+
+	dev->base_addr = 2;
+
+	printk("%s initialized\n", dev->name);
+
+	/* make Linux aware of the new hardware  */
+
+	if (!dev) {
+		printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n",
+                       cardname);
+		dev = init_etherdev(dev, sizeof(struct net_local));
+		if (!dev)
+			panic("init_etherdev failed\n");
+	}
+
+	/* setup generic handlers and stuff in the dev struct */
+
+	ether_setup(dev);
+
+	/* make room for the local structure containing stats etc */
+
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0, sizeof(struct net_local));
+
+	/* now setup our etrax specific stuff */
+
+	dev->irq = DMA3_RX_IRQ_NBR; /* we really use DMATX as well... */
+        dev->dma = PAR0_RX_DMA_NBR;
+
+	/* fill in our handlers so the network layer can talk to us in the future */
+
+	dev->open               = e100_open;
+	dev->hard_start_xmit    = e100_send_packet;
+	dev->stop               = e100_close;
+	dev->get_stats          = e100_get_stats;
+	dev->set_multicast_list = set_multicast_list;
+	dev->set_mac_address    = e100_set_mac_address;
+        
+        /* set the default MAC address */
+
+	e100_set_mac_address(dev, &default_mac);
+
+	/* Initialise the list of Etrax DMA-descriptors */
+
+	/* Initialise receive descriptors */
+
+	for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+		RxDescList[i].ctrl   = 0;
+		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+		RxDescList[i].next   = virt_to_phys(&RxDescList[i + 1]);
+		RxDescList[i].buf    = virt_to_phys(RxBuf + anOffset);
+		RxDescList[i].status = 0;
+		RxDescList[i].hw_len = 0;
+		anOffset += RX_DESC_BUF_SIZE;
+	}
+
+	RxDescList[i].ctrl   = d_eol;
+	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+	RxDescList[i].next   = virt_to_phys(&RxDescList[0]);
+	RxDescList[i].buf    = virt_to_phys(RxBuf + anOffset);
+	RxDescList[i].status = 0;
+	RxDescList[i].hw_len = 0;
+
+	/* Initialise initial pointers */
+
+	myNextRxDesc = &RxDescList[0];
+	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+
+        /* setup some TX descriptor data */
+
+	TxDescList[0].sw_len = 4;
+	TxDescList[0].ctrl = 0;
+	TxDescList[0].buf = virt_to_phys(&host_command);
+	TxDescList[0].next = virt_to_phys(&TxDescList[1]);
+
+	return 0;
+}
+
+/* set MAC address of the interface. called from the core after a
+ * SIOCSIFADDR ioctl, and from the bootup above.
+ */
+
+static int
+e100_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	int i;
+
+	/* remember it */
+
+        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/* Write it to the hardware.
+	 * Note the way the address is wrapped:
+	 * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24);
+	 * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8);
+	 */
+
+        tx_skb = 0;
+	e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6);
+
+	/* show it in the log as well */
+
+	printk("%s: changed MAC to ", dev->name);
+
+	for (i = 0; i < 5; i++)
+		printk("%02X:", dev->dev_addr[i]);
+
+	printk("%02X\n", dev->dev_addr[i]);
+
+	return 0;
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+static int
+e100_open(struct net_device *dev)
+{
+	unsigned long flags;
+
+	/* configure the PAR0 (RX) and PAR1 (TX) ports
+	 *
+	 * perror is nAckReverse, which must be 1 at the TX side,
+         * and 0 at the RX side
+         *
+	 * select is XFlag, which must be 1 at both sides
+	 */
+#ifdef ETHDEBUG        
+        printk("Setting up PAR ports\n");
+#endif
+        *R_PAR0_CONFIG =
+          /* We do not have an external buffer, don't care */
+		IO_STATE(R_PAR0_CONFIG, ioe,     noninv)    |
+          /* Not connected, don't care */
+		IO_STATE(R_PAR0_CONFIG, iseli,   noninv)    |
+          /* iautofd is not inverted, noninv */
+		IO_STATE(R_PAR0_CONFIG, iautofd, noninv)    |
+          /* Not used in reverse direction, don't care */
+		IO_STATE(R_PAR0_CONFIG, istrb,   noninv)    |
+          /* Not connected, don't care /
+		IO_STATE(R_PAR0_CONFIG, iinit,   noninv)    |
+          /* perror is GND and reverse wants 0, noninv */
+		IO_STATE(R_PAR0_CONFIG, iperr,   noninv)    |
+          /* ack is not inverted, noninv */
+		IO_STATE(R_PAR0_CONFIG, iack,    noninv)    |
+          /* busy is not inverted, noninv */
+		IO_STATE(R_PAR0_CONFIG, ibusy,   noninv)    |
+          /* fault is not inverted, noninv */
+		IO_STATE(R_PAR0_CONFIG, ifault,  noninv)    |
+          /* select is Vcc and we want 1, noninv */
+		IO_STATE(R_PAR0_CONFIG, isel,    noninv)    |
+          /* We will run dma, enable */
+		IO_STATE(R_PAR0_CONFIG, dma, enable)        |
+          /* No run length encoding, disable */
+		IO_STATE(R_PAR0_CONFIG, rle_in, disable)    |
+          /* No run length encoding, disable */
+		IO_STATE(R_PAR0_CONFIG, rle_out, disable)   |
+          /* Enable parallel port */
+		IO_STATE(R_PAR0_CONFIG, enable, on)         |
+          /* Force mode regardless of pin status */
+		IO_STATE(R_PAR0_CONFIG, force, on)          |
+          /* We want ECP forward mode since PAR0 is RX */
+		IO_STATE(R_PAR0_CONFIG, mode, ecp_rev);       
+
+        *R_PAR1_CONFIG =
+          /* We do not have an external buffer, don't care */
+		IO_STATE(R_PAR1_CONFIG, ioe,     noninv)    |
+          
+          /* Not connected, don't care */
+		IO_STATE(R_PAR1_CONFIG, iseli,   noninv)    |
+          
+          /* HostAck must indicate data cycle, noninv */
+		IO_STATE(R_PAR1_CONFIG, iautofd, noninv)    |
+          
+          /* HostClk has no external inverter, noninv */
+		IO_STATE(R_PAR1_CONFIG, istrb,   noninv)    |
+          
+          /* Not connected, don't care */
+		IO_STATE(R_PAR1_CONFIG, iinit,   noninv)    |
+          
+          /* nAckReverse must be 1 in forward mode but is grounded, inv */ 
+		IO_STATE(R_PAR1_CONFIG, iperr,   inv)       |
+          
+          /* PeriphClk must be 1 in forward mode, noninv */
+		IO_STATE(R_PAR1_CONFIG, iack,    noninv)    |
+          
+          /* PeriphAck has no external inverter, noninv */
+		IO_STATE(R_PAR1_CONFIG, ibusy,   noninv)    |
+          
+          /* nPerihpRequest has no external inverter, noniv */
+		IO_STATE(R_PAR1_CONFIG, ifault,  noninv)    |
+          
+          /* Select is VCC and we want 1, noninv */
+		IO_STATE(R_PAR1_CONFIG, isel,    noninv)    |
+          
+          /* No EPP mode, disable */
+                IO_STATE(R_PAR1_CONFIG, ext_mode, disable)  |
+          
+          /* We will run dma, enable */
+                IO_STATE(R_PAR1_CONFIG, dma, enable)        |
+          
+          /* No run length encoding, disable */
+		IO_STATE(R_PAR1_CONFIG, rle_in, disable)    |
+          
+          /* No run length encoding, disable */
+		IO_STATE(R_PAR1_CONFIG, rle_out, disable)   |
+          
+          /* Enable parallel port */
+		IO_STATE(R_PAR1_CONFIG, enable, on)         |
+          
+          /* Force mode regardless of pin status */
+		IO_STATE(R_PAR1_CONFIG, force, on)          |
+          
+          /* We want ECP forward mode since PAR1 is TX */
+	 	IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd);        
+
+        /* Setup time of value * 160 + 20 ns == 180 ns below */
+        *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 1);  
+
+        *R_PAR1_CTRL = 0;
+
+        while ((((*R_PAR1_STATUS)&0xE000) >> 13) != 5); /* Wait for ECP_FWD mode */
+#ifdef ETHDEBUG
+        dump_parport_status();
+#endif
+        
+        /* make sure ECP irq is acked when we enable it below */
+
+	(void)*R_PAR0_STATUS_DATA;
+	(void)*R_PAR1_STATUS_DATA;
+
+	/* Reset and wait for the DMA channels */
+
+        RESET_DMA(4); /* PAR1_TX_DMA_NBR */
+	RESET_DMA(3); /* PAR0_RX_DMA_NBR */
+	WAIT_DMA(4);  
+	WAIT_DMA(3);
+        
+        /* boot the slave Etrax, by sending code on PAR1.
+	 * do this before we start up the IRQ handlers and stuff,
+	 * beacuse we simply poll for completion in boot_slave.
+	 */
+        
+	boot_slave(&e100lpslaveprog);
+
+	/* allocate the irq corresponding to the receiving DMA */
+
+	if (request_irq(DMA3_RX_IRQ_NBR, e100rx_interrupt, 0,
+			cardname, (void *)dev)) {
+          printk("Failed to allocate DMA3_RX_IRQ_NBR\n");
+		goto grace_exit;
+	}
+
+	/* allocate the irq corresponding to the transmitting DMA */
+
+	if (request_irq(DMA4_TX_IRQ_NBR, e100tx_interrupt, 0,
+			cardname, (void *)dev)) {
+          printk("Failed to allocate DMA4_TX_IRQ_NBR\n");
+          goto grace_exit;
+	}
+        
+        /* allocate the irq used for detecting ECP commands on the RX port (PAR0) */
+
+	if (request_irq(PAR0_ECP_IRQ_NBR, ecp_interrupt, 0,
+			cardname, (void *)dev)) {
+          printk("Failed to allocate PAR0_ECP_IRQ_NBR\n");
+          grace_exit:          
+                free_irq(PAR0_ECP_IRQ_NBR, (void *)dev);
+                free_irq(DMA4_TX_IRQ_NBR, (void *)dev);
+		free_irq(DMA3_RX_IRQ_NBR, (void *)dev);
+                
+		return -EAGAIN;
+	}
+
+#if 0
+        /* We are not allocating DMA since DMA4 is reserved for 'cascading'
+         * and will always fail with the current dma.c
+         */
+        
+	/*
+	 * Always allocate the DMA channels after the IRQ,
+	 * and clean up on failure.
+	 */
+
+	if(request_dma(PAR0_RX_DMA_NBR, cardname)) {
+          printk("Failed to allocate PAR0_RX_DMA_NBR\n");
+		goto grace_exit;
+	}
+
+	if(request_dma(PAR1_TX_DMA_NBR, cardname)) {
+          printk("Failed to allocate PAR1_TX_DMA_NBR\n");
+	grace_exit:
+		/* this will cause some 'trying to free free irq' but what the heck... */
+
+		free_dma(PAR1_TX_DMA_NBR);
+                free_dma(PAR0_RX_DMA_NBR);
+                free_irq(PAR0_ECP_IRQ_NBR, (void *)dev);
+                free_irq(DMA4_TX_IRQ_NBR, (void *)dev);
+		free_irq(DMA3_RX_IRQ_NBR, (void *)dev);
+		
+		return -EAGAIN;
+	}
+#endif
+        
+#ifdef ETHDEBUG
+        printk("Par port IRQ and DMA allocated\n");
+#endif
+	save_flags(flags);
+	cli();
+
+	/* enable the irq's for PAR0/1 DMA */
+
+	*R_IRQ_MASK2_SET =
+		IO_STATE(R_IRQ_MASK2_SET, dma3_eop, set) |
+		IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set);
+
+        *R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, par0_ecp_cmd, set);
+
+	tx_skb = 0;
+
+	/* make sure the irqs are cleared */
+
+	*R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do);
+	*R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do);
+
+        /* Write the MAC address to the slave HW */
+	udelay(5000);
+	e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6);
+        
+	/* make sure the rec and transmit error counters are cleared */
+
+	(void)*R_REC_COUNTERS;  /* dummy read */
+	(void)*R_TR_COUNTERS;   /* dummy read */
+
+	/* start the receiving DMA channel so we can receive packets from now on */
+
+	*R_DMA_CH3_FIRST = virt_to_phys(myNextRxDesc);
+	*R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+	restore_flags(flags);
+	
+	/* We are now ready to accept transmit requeusts from
+	 * the queueing layer of the networking.
+	 */
+#ifdef ETHDEBUG
+        printk("Starting slave network transmit queue\n");
+#endif
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static void 
+e100_reset_tranceiver(void)
+{
+  /* To do: Reboot and setup slave Etrax */
+}
+
+/* Called by upper layers if they decide it took too long to complete
+ * sending a packet - we need to reset and stuff.
+ */
+
+static void
+e100_tx_timeout(struct net_device *dev)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+	       tx_done(dev) ? "IRQ problem" : "network cable problem");
+	
+	/* remember we got an error */
+	
+	np->stats.tx_errors++; 
+	
+	/* reset the TX DMA in case it has hung on something */
+	
+	RESET_DMA(4);
+	WAIT_DMA(4);
+	
+	/* Reset the tranceiver. */
+	
+	e100_reset_tranceiver();
+	
+	/* and get rid of the packet that never got an interrupt */
+	
+	dev_kfree_skb(tx_skb);
+	tx_skb = 0;
+	
+	/* tell the upper layers we're ok again */
+	
+	netif_wake_queue(dev);
+}
+
+
+/* This will only be invoked if the driver is _not_ in XOFF state.
+ * What this means is that we need not check it, and that this
+ * invariant will hold if we make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+
+static int
+e100_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+	int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char *buf = skb->data;
+	
+#ifdef ETHDEBUG
+        unsigned char *temp_data_ptr = buf;
+        int i;
+        
+	printk("Sending a packet of length %d:\n", length);
+	/* dump the first bytes in the packet */
+	for(i = 0; i < 8; i++) {
+		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
+		       temp_data_ptr[0],temp_data_ptr[1],temp_data_ptr[2],
+                       temp_data_ptr[3],temp_data_ptr[4],temp_data_ptr[5],
+                       temp_data_ptr[6],temp_data_ptr[7]);
+		temp_data_ptr += 8;
+	}
+#endif
+	spin_lock_irq(&np->lock);  /* protect from tx_interrupt */
+
+	tx_skb = skb; /* remember it so we can free it in the tx irq handler later */
+	dev->trans_start = jiffies;
+	
+	e100_hardware_send_packet(HOST_CMD_SENDPACK, buf, length);
+
+	/* this simple TX driver has only one send-descriptor so we're full
+	 * directly. If this had a send-ring instead, we would only do this if
+	 * the ring got full.
+	 */
+
+	netif_stop_queue(dev);
+        
+	spin_unlock_irq(&np->lock);
+
+	return 0;
+}
+
+/*
+ * The typical workload of the driver:
+ *   Handle the network interface interrupts.
+ */
+
+static void
+e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	unsigned long irqbits = *R_IRQ_MASK2_RD;
+        
+	if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma3_eop, active)) {
+
+		/* acknowledge the eop interrupt */
+
+		*R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do);
+
+		/* check if one or more complete packets were indeed received */
+
+		while(*R_DMA_CH3_FIRST != virt_to_phys(myNextRxDesc)) {
+			/* Take out the buffer and give it to the OS, then
+			 * allocate a new buffer to put a packet in.
+			 */
+			e100_rx(dev);
+			((struct net_local *)dev->priv)->stats.rx_packets++;
+			/* restart/continue on the channel, for safety */
+			*R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, restart);
+			/* clear dma channel 3 eop/descr irq bits */
+			*R_DMA_CH3_CLR_INTR =
+				IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do) |
+				IO_STATE(R_DMA_CH3_CLR_INTR, clr_descr, do);
+			
+			/* now, we might have gotten another packet
+			   so we have to loop back and check if so */
+		}
+	}
+}
+
+/* the transmit dma channel interrupt
+ *
+ * this is supposed to free the skbuff which was pending during transmission,
+ * and inform the kernel that we can send one more buffer
+ */
+
+static void
+e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	unsigned long irqbits = *R_IRQ_MASK2_RD;
+	struct net_local *np = (struct net_local *)dev->priv;
+
+#ifdef ETHDEBUG
+        printk("We got tx interrupt\n");
+#endif
+	/* check for a dma4_eop interrupt */
+	if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma4_descr, active)) {
+		/* This protects us from concurrent execution of
+		 * our dev->hard_start_xmit function above.
+		 */
+
+		spin_lock(&np->lock);
+		
+		/* acknowledge the eop interrupt */
+                
+		*R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do);
+
+                /* skip *R_DMA_CH4_FIRST == 0 test since we use d_wait... */
+		if(tx_skb) {
+
+			np->stats.tx_bytes += tx_skb->len;
+			np->stats.tx_packets++;
+			/* dma is ready with the transmission of the data in tx_skb, so now we can release the skb memory */
+			dev_kfree_skb_irq(tx_skb);
+			tx_skb = 0;
+			netif_wake_queue(dev);
+		} else {
+			printk(KERN_WARNING "%s: tx weird interrupt\n",
+                               cardname);
+		}
+
+		spin_unlock(&np->lock);
+	}
+}
+
+static void
+ecp_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long temp, irqbits = *R_IRQ_MASK0_RD;
+
+        /* check for ecp irq */
+	if(irqbits & IO_MASK(R_IRQ_MASK0_RD, par0_ecp_cmd)) { 
+		/* acknowledge by reading the bit */
+		temp = *R_PAR0_STATUS_DATA;
+		/* force an EOP on the incoming channel, so we'll get an rx interrupt */
+		*R_SET_EOP = IO_STATE(R_SET_EOP, ch3_eop, set);
+	}
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+e100_rx(struct net_device *dev)
+{
+	struct sk_buff *skb;
+	int length=0;
+	int i;
+	struct net_local *np = (struct net_local *)dev->priv;
+	struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc;
+	unsigned char *skb_data_ptr;
+
+	/* If the packet is broken down in many small packages then merge
+	 * count how much space we will need to alloc with skb_alloc() for
+	 * it to fit.
+	 */
+
+	while (!(myNextRxDesc->status & d_eop)) {
+		length += myNextRxDesc->sw_len; /* use sw_len for the first descs */
+		myNextRxDesc->status = 0;
+		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+	}
+
+	length += myNextRxDesc->hw_len; /* use hw_len for the last descr */
+
+#ifdef ETHDEBUG
+	printk("Got a packet of length %d:\n", length);
+	/* dump the first bytes in the packet */
+	skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf);
+	for(i = 0; i < 8; i++) {
+		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
+		       skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
+		       skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
+		skb_data_ptr += 8;
+	}
+#endif
+
+	skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
+	if (!skb) {
+		np->stats.rx_errors++;
+		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+		       dev->name);
+		return;
+	}
+
+	skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
+	skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
+
+#ifdef ETHDEBUG
+	printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
+	       skb->head, skb->data, skb->tail, skb->end);
+	printk("copying packet to 0x%x.\n", skb_data_ptr);
+#endif
+
+	/* this loop can be made using max two memcpy's if optimized */
+
+	while(mySaveRxDesc != myNextRxDesc) {
+		memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
+		       mySaveRxDesc->sw_len);
+		skb_data_ptr += mySaveRxDesc->sw_len;
+		mySaveRxDesc = phys_to_virt(mySaveRxDesc->next);
+	}
+
+	memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
+	       mySaveRxDesc->hw_len);
+
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+
+	/* Send the packet to the upper layers */
+
+	netif_rx(skb);
+
+	/* Prepare for next packet */
+
+	myNextRxDesc->status = 0;
+	myPrevRxDesc = myNextRxDesc;
+	myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+
+	myPrevRxDesc->ctrl |= d_eol;
+	myLastRxDesc->ctrl &= ~d_eol;
+	myLastRxDesc = myPrevRxDesc;
+
+	return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+e100_close(struct net_device *dev)
+{
+	struct net_local *np = (struct net_local *)dev->priv;
+
+	printk("Closing %s.\n", dev->name);
+
+	netif_stop_queue(dev);
+
+	*R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, par0_ecp_cmd, clr);
+
+	*R_IRQ_MASK2_CLR =
+		IO_STATE(R_IRQ_MASK2_CLR, dma3_eop, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr);	
+
+	/* Stop the receiver and the transmitter */
+
+	RESET_DMA(3);
+	RESET_DMA(4);
+
+	/* Flush the Tx and disable Rx here. */
+
+	free_irq(DMA3_RX_IRQ_NBR, (void *)dev);
+	free_irq(DMA4_TX_IRQ_NBR, (void *)dev);
+	free_irq(PAR0_ECP_IRQ_NBR, (void *)dev);
+
+	free_dma(PAR1_TX_DMA_NBR);
+	free_dma(PAR0_RX_DMA_NBR);
+
+	/* Update the statistics here. */
+
+	update_rx_stats(&np->stats);
+	update_tx_stats(&np->stats);
+
+	return 0;
+}
+
+static void
+update_rx_stats(struct net_device_stats *es)
+{
+	unsigned long r = *R_REC_COUNTERS;
+	/* update stats relevant to reception errors */
+	es->rx_fifo_errors += r >> 24;            /* fifo overrun */
+	es->rx_crc_errors += r & 0xff;            /* crc error */
+	es->rx_frame_errors += (r >> 8) & 0xff;   /* alignment error */
+	es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */
+}
+
+static void
+update_tx_stats(struct net_device_stats *es)
+{
+	unsigned long r = *R_TR_COUNTERS;
+	/* update stats relevant to transmission errors */
+	es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */
+	es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	update_rx_stats(&lp->stats);
+	update_tx_stats(&lp->stats);
+
+	return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+  /* To do */
+}
+
+void
+e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length)
+{
+  static char bogus_ecp[] = { 42, 42 };
+  int i;
+  
+
+#ifdef ETHDEBUG
+	printk("e100 send pack, buf 0x%x len %d\n", buf, length);
+#endif
+        
+        host_command = hostcmd;
+
+	/* Configure the tx dma descriptor. Desc 0 is already configured.*/
+
+        TxDescList[1].sw_len = length;
+	/* bug workaround - etrax100 needs d_wait on the descriptor _before_
+	 * a descriptor containing an ECP command
+	 */
+	TxDescList[1].ctrl = d_wait;
+	TxDescList[1].buf = virt_to_phys(buf);
+	TxDescList[1].next = virt_to_phys(&TxDescList[2]);
+
+        /* append the ecp dummy descriptor - its only purpose is to 
+	 * make the receiver generate an irq due to the ecp command
+	 * so the receiver knows where packets end
+	 */
+
+	TxDescList[2].sw_len = 1;
+	TxDescList[2].ctrl = d_ecp | d_eol | d_int;
+	TxDescList[2].buf = virt_to_phys(bogus_ecp);
+        
+
+	/* setup the dma channel and start it */
+
+        *R_DMA_CH4_FIRST = virt_to_phys(TxDescList);
+	*R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start);
+        
+#ifdef ETHDEBUG         
+         printk("done\n");
+#endif
+}
+
+/* send a chunk of code to the slave chip to boot it. */
+
+static void
+boot_slave(unsigned char *code)
+{
+  int i;
+
+#ifdef ETHDEBUG
+	printk("  booting slave ETRAX...\n");
+#endif
+        *R_PORT_PB_DATA = 0x7F; /* Reset slave */
+        udelay(15); /* Time enough to reset WAN tranciever */
+        *R_PORT_PB_DATA = 0xFF; /* Reset slave */
+
+	/* configure the tx dma data descriptor */
+
+	TxDescList[1].sw_len = ETRAX_PAR_BOOT_LENGTH;
+	TxDescList[1].ctrl = d_eol | d_int; 
+                                                      
+	TxDescList[1].buf = virt_to_phys(code);
+        /*TxDescList[1].buf = code;*/
+	TxDescList[1].next = 0;
+        
+        /* setup the dma channel and start it */
+ 	*R_DMA_CH4_FIRST = virt_to_phys(&TxDescList[1]);
+	*R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start);
+
+	/* wait for completion */
+	while(!(*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma4_descr)));
+
+	/* ack the irq */
+
+	*R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do);
+
+#if 0
+        /* manual transfer of boot code - requires dma turned off */
+        for (i=0; i<ETRAX_PAR_BOOT_LENGTH; i++)
+        {
+          printk("  sending byte: %u value: %x\n",i,code[i]);
+          while (((*R_PAR1_STATUS)&0x02) == 0); /* Wait while tr_rdy is busy*/
+          *R_PAR1_CTRL_DATA = code[i];
+        }
+#endif
+
+#ifdef ETHDEBUG
+	printk("  done\n");
+#endif
+}
+
+#ifdef ETHDEBUG
+/* debug code to check the current status of PAR1 */
+static void
+dump_parport_status(void)
+{
+  unsigned long temp;
+  
+  printk("Parport1 status:\n");
+  
+  temp = (*R_PAR1_STATUS)&0xE000;
+  temp = temp >> 13;
+  printk("Reg mode: %u (ecp_fwd(5), ecp_rev(6))\n", temp);
+  
+  temp = (*R_PAR1_STATUS)&0x1000;
+  temp = temp >> 12;
+  printk("Reg perr: %u (ecp_rev(0))\n", temp);
+  
+  temp = (*R_PAR1_STATUS)&0x0800;
+  temp = temp >> 11;
+  printk("Reg ack: %u (inactive (1), active (0))\n", temp);
+  
+  temp = (*R_PAR1_STATUS)&0x0400;
+  temp = temp >> 10;
+  printk("Reg busy: %u (inactive (0), active (1))\n", temp);
+  
+  temp = (*R_PAR1_STATUS)&0x0200;
+  temp = temp >> 9;
+  printk("Reg fault: %u (inactive (1), active (0))\n", temp);
+  
+  temp = (*R_PAR1_STATUS)&0x0100;
+  temp = temp >> 8;
+  printk("Reg sel: %u (inactive (0), active (1), xflag(1))\n", temp);
+
+  temp = (*R_PAR1_STATUS)&0x02;
+  temp = temp >> 1;
+  printk("Reg tr_rdy: %u (busy (0), ready (1))\n", temp);
+
+}
+#endif /* ETHDEBUG */
+
+static struct net_device dev_etrax_slave_ethernet;
+
+static int
+etrax_init_module(void)
+{
+	struct net_device *d = &dev_etrax_slave_ethernet;
+
+	d->init = etrax_ethernet_lpslave_init;
+
+	if(register_netdev(d) == 0)
+		return 0;
+	else
+		return -ENODEV;
+}
+
+module_init(etrax_init_module);
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c
--- v2.4.6/linux/arch/cris/drivers/parport.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/parport.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $
+/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -501,8 +501,8 @@
 
 #ifdef CONFIG_ETRAX_PARALLEL_PORT0
 #ifdef CONFIG_ETRAX_PAR0_DMA
-	RESET_DMA(2);
-	WAIT_DMA(2);
+	RESET_DMA(PAR0_TX_DMA_NBR);
+	WAIT_DMA(PAR0_TX_DMA_NBR);
 #ifdef CONFIG_ETRAX_SERIAL_PORT2
 	printk(" Warning - DMA clash with ser2!\n");
 #endif /* SERIAL_PORT2 */
@@ -511,8 +511,8 @@
 
 #ifdef CONFIG_ETRAX_PARALLEL_PORT1
 #ifdef CONFIG_ETRAX_PAR1_DMA
-	RESET_DMA(4);
-	WAIT_DMA(4);
+	RESET_DMA(PAR1_TX_DMA_NBR);
+	WAIT_DMA(PAR1_TX_DMA_NBR);
 #ifdef CONFIG_ETRAX_SERIAL_PORT3
 	printk(" Warning - DMA clash with ser3!\n");
 #endif /* SERIAL_PORT3 */
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c
--- v2.4.6/linux/arch/cris/drivers/serial.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/serial.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $
+/* $Id: serial.c,v 1.13 2001/05/09 12:40:31 johana Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,9 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.13  2001/05/09 12:40:31  johana
+ * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
+ *
  * Revision 1.12  2001/04/19 12:23:07  bjornw
  * CONFIG_RS485 -> CONFIG_ETRAX_RS485
  *
@@ -199,7 +202,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.12 $";
+static char *serial_version = "$Revision: 1.13 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -495,7 +498,6 @@
 #endif
 
 #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
-#define TIMER1_IRQ_NBR 3
 
 /* clock select 10 for timer 1 gives 230400 Hz */
 #define FASTTIMER_SELECT (10)
@@ -3049,32 +3051,32 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* Not needed in simulator.  May only complicate stuff. */
 	/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
-	if(request_irq(22, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
+	if(request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
 		panic("irq22");
-	if(request_irq(23, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
+	if(request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
 		panic("irq23");
 #ifdef SERIAL_HANDLE_EARLY_ERRORS
-	if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL))
+	if(request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL))
 		panic("irq8");
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT1
-	if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
+	if(request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
 		panic("irq24");
-	if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
+	if(request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
 		panic("irq25");
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT2
 	/* DMA Shared with par0 (and SCSI0 and ATA) */
-	if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL))
+	if(request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL))
 		panic("irq18");
-	if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL))
+	if(request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL))
 		panic("irq19");
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT3
 	/* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
-	if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL))
+	if(request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL))
 		panic("irq20");
-	if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL))
+	if(request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL))
 		panic("irq21");
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c
--- v2.4.6/linux/arch/cris/drivers/usb-host.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/drivers/usb-host.c	Wed Jul  4 11:50:39 2001
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2001 Axis Communications AB.
  *
- * $Id: usb-host.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $
+ * $Id: usb-host.c,v 1.9 2001/05/09 12:54:12 johana Exp $
  *
  */
 
@@ -23,17 +23,18 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/svinto.h>
 
 #include <linux/usb.h>
 #include "usb-host.h"
 
-#define ETRAX_USB_HC_IRQ 31
-#define ETRAX_USB_RX_IRQ 25
-#define ETRAX_USB_TX_IRQ 24
+#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
+#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
+#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
 
-static const char *usb_hcd_version = "$Revision: 1.8 $";
+static const char *usb_hcd_version = "$Revision: 1.9 $";
 
 #undef KERN_DEBUG
 #define KERN_DEBUG ""
@@ -2034,21 +2035,21 @@
 		OK (4);		/* hub power ** */
 		
 	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-                if (wIndex == 1) {
+		if (wIndex == 1) {
 			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
 			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
-                }
-                else if (wIndex == 2) {
+		}
+		else if (wIndex == 2) {
 			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
 			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
-                }
-                else {
+		}
+		else {
 			dbg_rh("RH_GET_STATUS whith invalid wIndex !!");
 			OK(0);
-                }
+		}
 		
-                OK(4);
-                
+		OK(4);
+
 	case RH_CLEAR_FEATURE | RH_ENDPOINT:
 		switch (wValue) {
 		case (RH_ENDPOINT_STALL):
@@ -2114,16 +2115,16 @@
 			OK (0);	/* port power ** */
 		case (RH_C_PORT_CONNECTION):
 			
-                        if (wIndex == 1) {
+			if (wIndex == 1) {
 				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
-                        }
-                        else if (wIndex == 2) {
+			}
+			else if (wIndex == 2) {
 				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
-                        }
-                        else {
+			}
+			else {
 				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
 				       "with invalid wIndex == %d!!", wIndex);
-                        }
+			}
 
 			OK (0);
 		case (RH_C_PORT_ENABLE):
@@ -2182,7 +2183,7 @@
 
 			OK (0);
 		case (RH_PORT_RESET):
-                        if (wIndex == 1) {
+			if (wIndex == 1) {
 				int port1_retry;
 				
 			port1_redo:
@@ -2205,8 +2206,8 @@
 				   not even schedule() works !!! WHY ?? */
 
 				udelay(15000);
-                        }
-                        else if (wIndex == 2) {
+			}
+			else if (wIndex == 2) {
 				int port2_retry;
 				
 			port2_redo:
@@ -2229,7 +2230,7 @@
 				   not even schedule() works !!! WHY ?? */
 
 				udelay(15000);
-                        }
+			}
 
 			/* Try to bring the HC into running state */
 			*R_USB_COMMAND =
@@ -2237,21 +2238,21 @@
 			
 			nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
 			
-                        dbg_rh("...Done");
-                        OK(0);
-                        
+			dbg_rh("...Done");
+			OK(0);
+
 		case (RH_PORT_POWER):
 			OK (0);	/* port power ** */
 		case (RH_PORT_ENABLE):
 			/* There is no rh port enable command in the Etrax USB interface!!!! */
 			OK (0);
-                        
+
 		}
 		break;
 		
 	case RH_SET_ADDRESS:
 		hc->rh.devnum = wValue;
-                dbg_rh("RH address set to: %d", hc->rh.devnum);
+		dbg_rh("RH address set to: %d", hc->rh.devnum);
 		OK (0);
 		
 	case RH_GET_DESCRIPTOR:
@@ -2324,7 +2325,7 @@
 	etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
 	hc->bus = bus;
 	bus->hcpriv = hc;
-        
+
 	/* Initalize RH to the default address.
 	   And make sure that we have no status change indication */
 	hc->rh.numports = 2;  /* The RH has two ports */
@@ -2339,7 +2340,7 @@
 	/* Initialize the intr-traffic flags */
 	hc->intr.sleeping = 0;
 	hc->intr.wq = NULL;
-        
+
 	/* Initially all ep's are free except ep 0 */
 	ep_usage_bitmask = 0;
 	set_bit(0, (void *)&ep_usage_bitmask);
@@ -2349,20 +2350,20 @@
 
 	/* This code should really be moved */
 
-        if (request_dma(8, "ETRAX 100LX built-in USB (Tx)")) {
+	if (request_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)")) {
 		err("Could not allocate DMA ch 8 for USB");
 		etrax_usb_hc_cleanup();
 		DBFEXIT;
 		return -1;
 	}
 	
-	if (request_dma(9, "ETRAX 100LX built-in USB (Rx)")) {
+	if (request_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)")) {
 		err("Could not allocate DMA ch 9 for USB");
 		etrax_usb_hc_cleanup();
 		DBFEXIT;
 		return -1;
 	}	
-#if 0  /* Moved to head.S */        
+#if 0  /* Moved to head.S */
 	*R_GEN_CONFIG = genconfig_shadow =
 		(genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) |
 				      IO_MASK(R_GEN_CONFIG, usb2) |
@@ -2490,8 +2491,8 @@
 	free_irq(ETRAX_USB_RX_IRQ, NULL);
 	free_irq(ETRAX_USB_TX_IRQ, NULL);
 
-	free_dma(8);
-	free_dma(9);
+	free_dma(USB_TX_DMA_NBR);
+	free_dma(USB_RX_DMA_NBR);
 	usb_deregister_bus(etrax_usb_bus);
 
 	DBFEXIT;
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile
--- v2.4.6/linux/arch/cris/kernel/Makefile	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/Makefile	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $
+# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -19,6 +19,11 @@
 	   debugport.o semaphore.o
 
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
+
+entry.o: entryoffsets.s
+
+entryoffsets.s: entryoffsets.c
+	$(CC) $(CFLAGS) -S -c $<
 
 clean:
 
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
--- v2.4.6/linux/arch/cris/kernel/entry.S	Sun May 20 12:11:38 2001
+++ linux/arch/cris/kernel/entry.S	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $
+/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,21 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.27  2001/05/29 11:25:27  markusl
+ *  In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
+ *
+ *  Revision 1.26  2001/05/15 15:46:03  bjornw
+ *  Include config.h now that we use some CONFIG_ options
+ *
+ *  Revision 1.25  2001/05/15 05:38:47  hp
+ *  Tweaked code in _ret_from_sys_call
+ *
+ *  Revision 1.24  2001/05/15 05:27:49  hp
+ *  Save r9 in r1 over function call rather than on stack.
+ *
+ *  Revision 1.23  2001/05/15 05:10:00  hp
+ *  Generate entry.S structure offsets from C
+ *
  *  Revision 1.22  2001/04/17 13:58:39  orjanf
  *  * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
  *
@@ -140,39 +155,21 @@
 	
 LENOSYS = 38
 
-	;; offsets into the task_struct (found at sp aligned to THREAD_SIZE, 8192)
-	;; linux/sched.h
-	
-LTASK_SIGPENDING  =  8
-LTASK_NEEDRESCHED = 20
-LTASK_PTRACE      = 24
-LTASK_PID         = 105
+	;; Get offsets into various structs.
+	.include "entryoffsets.s"
 
-	;; process bits for ptrace
+	;; process bits for ptrace.  FIXME: Should be in a header file.
 
 PT_TRACESYS_BIT	  = 1
 
-	;; some pt_regs offsets (from ptrace.h)
-	
-LORIG_R10	= 4
-LR13		= 8
-LR12		= 12
-LR11		= 16
-LR10		= 20
-LR9		= 24
-LMOF		= 64
-LDCCR		= 68
-LSRP		= 72
-LIRP		= 76
-
 	;; below are various parts of system_call which are not in the fast-path
 	
 	;; handle software irqs
 				
 handle_softirq:
-	push	r9
+	move.d	r9,r1
 	jsr	_do_softirq		; call the C routine for softirq handling
-	pop	r9
+	move.d	r1,r9
 
 	;; fall-through
 	
@@ -188,11 +185,10 @@
 
 reschedule:
 	;; keep r9 intact
-	push	r9
+	move.d	r9,r1
 	jsr	_schedule
-	pop	r9
 	ba	_ret_from_sys_call
-	nop
+	move.d	r1,r9
 
 	;; return but call do_signal first
 signal_return:
@@ -275,8 +271,9 @@
 		
 	;; check if any bottom halves need service
 	
-	move.d	[_irq_stat],r0	       ; softirq_active
-	and.d	[_irq_stat+4],r0       ; softirq_mask
+	move.d	_irq_stat,r10
+	move.d	[r10+],r0	       ; softirq_active
+	and.d	[r10],r0	       ; softirq_mask
 	bne	handle_softirq
 	nop
 
@@ -378,12 +375,6 @@
 	ba	_ret_from_sys_call
 	nop
 		
-	;; from asm/processor.h, the thread_struct
-	
-LTHREAD_KSP	= 0
-LTHREAD_USP	= 4
-LTHREAD_DCCR	= 8
-	
 	;; _resume performs the actual task-switching, by switching stack pointers
 	;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
 	;; returns old current in r10
@@ -495,7 +486,7 @@
 _IRQ1_interrupt:
 _spurious_interrupt:	
 	di
-basse2:	ba	basse2
+	jsr _hard_reset_now
 	nop
 
 	;; this handles the case when multiple interrupts arrive at the same time
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/entryoffsets.c linux/arch/cris/kernel/entryoffsets.c
--- v2.4.6/linux/arch/cris/kernel/entryoffsets.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/kernel/entryoffsets.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,54 @@
+/* linux/arch/cris/entryoffsets.c
+ *
+ * Copyright (C) 2001 Axis Communications AB
+ *
+ * Generate structure offsets for use in entry.S.  No extra processing
+ * needed more than compiling this file to assembly code.  Horrendous
+ * assembly code will be generated, so don't look at that.
+ *
+ * Authors:	Hans-Peter Nilsson (hp@axis.com)
+ */
+
+/* There can be string constants fallout from inline functions, so we'd
+   better make sure we don't assemble anything emitted from inclusions.  */
+__asm__ (".if 0");
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <asm/processor.h>
+
+/* Exclude everything except the assembly by wrapping it in ".if 0".  */
+#undef OF
+#define OF(NAME, TYPE, MEMBER)			\
+void NAME ## _fun (void)			\
+ {						\
+  __asm__ (".endif \n"				\
+	   #NAME " = %0 \n"			\
+	   ".if 0\n"				\
+	   : : "i" (offsetof (TYPE, MEMBER)));	\
+ }
+
+/* task_struct offsets.  */
+OF (LTASK_SIGPENDING, struct task_struct, sigpending)
+OF (LTASK_NEEDRESCHED, struct task_struct, need_resched)
+OF (LTASK_PTRACE, struct task_struct, ptrace)
+OF (LTASK_PID, struct task_struct, pid)
+
+/* pt_regs offsets.  */
+OF (LORIG_R10, struct pt_regs, orig_r10)
+OF (LR13, struct pt_regs, r13)
+OF (LR12, struct pt_regs, r12)
+OF (LR11, struct pt_regs, r11)
+OF (LR10, struct pt_regs, r10)
+OF (LR9, struct pt_regs, r9)
+OF (LMOF, struct pt_regs, mof)
+OF (LDCCR, struct pt_regs, dccr)
+OF (LSRP, struct pt_regs, srp)
+OF (LIRP, struct pt_regs, irp)
+
+/* thread_struct offsets.  */
+OF (LTHREAD_KSP, struct thread_struct, ksp)
+OF (LTHREAD_USP, struct thread_struct, usp)
+OF (LTHREAD_DCCR, struct thread_struct, dccr)
+
+__asm__ (".endif");
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S
--- v2.4.6/linux/arch/cris/kernel/head.S	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/head.S	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $
+/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $
  * 
  * Head of the kernel - alter with care
  *
@@ -7,6 +7,21 @@
  * Authors:	Bjorn Wesen (bjornw@axis.com)
  * 
  * $Log: head.S,v $
+ * Revision 1.34  2001/05/15 07:08:14  hp
+ * Tweak "notice" to reflect that both r8 r9 are used
+ *
+ * Revision 1.33  2001/05/15 06:40:05  hp
+ * Put bulk of code in .text.init, data in .data.init
+ *
+ * Revision 1.32  2001/05/15 06:18:56  hp
+ * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g
+ *
+ * Revision 1.31  2001/05/15 06:08:40  hp
+ * Add sentence about autodetecting the bit31-MMU-bug
+ *
+ * Revision 1.30  2001/05/15 06:00:05  hp
+ * Update comment: LOW_MAP is not forced on xsim anymore.
+ *
  * Revision 1.29  2001/04/18 12:51:59  orjanf
  * * Reverted review change regarding the use of bcs/bcc.
  * * Removed non-working LED-clearing code.
@@ -127,9 +142,9 @@
 	;; since etrax actually starts at address 2 when booting from flash, we
 	;; put a nop (2 bytes) here first so we dont accidentally skip the di
 	;;
-	;; NOTICE! The registers r8 and r9 are used as a parameter carrying
+	;; NOTICE! The registers r8 and r9 are used as parameters carrying
 	;; information from the decompressor (if the kernel was compressed). 
-	;; They should not be used in the code below until it is read.
+	;; They should not be used in the code below until read.
 	
 	nop	
 	di
@@ -143,8 +158,11 @@
 	;; temporarily map those segments linearily.
 	;;
 	;; Due to a bug in Etrax-100 LX version 1 we need to map the memory
-	;; slightly different. We also let the simulator get this mapping for now.
-	;; (The bug is that you can't remap bit 31.)
+	;; slightly different.  The bug is that you can't remap bit 31 of
+	;; an address.  Though we can check the version register for
+	;; whether the bug is present, some constants would then have to
+	;; be variables, so we don't.  The drawback is that you can "only" map
+	;; 1G per process with CONFIG_CRIS_LOW_MAP.
 
 #ifdef CONFIG_CRIS_LOW_MAP
 	move.d	0x0004b098, r0	; kseg mappings, temporary map of 0xc0->0x40
@@ -190,11 +208,18 @@
 	move.d	pc,r0
 	and.d	0x7fffffff,r0	; get rid of the non-cache bit
 	cmp.d	0x10000,r0	; arbitrary... just something above this code
-	bcs	inflash
+	blo	inflash0
 	nop
 
 	jump	inram		; enter cached ram
-	
+
+	;; Jumpgate for branches.
+inflash0:
+	jump	inflash
+
+	;; Put this in a suitable section where we can reclaim storage
+	;; after init.
+	.section ".text.init"
 inflash:
 	;; We need to initialze DRAM registers before we start using the DRAM
 
@@ -225,7 +250,7 @@
 1:	move.w	[r0+], r3
 	move.w	r3, [r1+]
 	cmp.d	r2, r1
-	bcs	1b
+	blo	1b
 	nop
 
 	;; We keep the cramfs in the flash.
@@ -271,7 +296,7 @@
 	;;  to a cramfs magic is small.. )
 	
 	cmp.d	0x0ffffff8, r9
-	bcc	no_romfs_in_flash	; r9 points outside the flash area
+	bhs	no_romfs_in_flash	; r9 points outside the flash area
 	nop
 	move.d	[r9], r0	; cramfs_super.magic
 	cmp.d	CRAMFS_MAGIC, r0
@@ -353,7 +378,7 @@
 	move.d	_end, r1
 1:	clear.d	[r0+]
 	cmp.d	r1, r0
-	bcs	1b
+	blo	1b
 	nop
 	
 #ifdef CONFIG_BLK_DEV_ETRAXIDE
@@ -575,5 +600,6 @@
 #else	
 _swapper_pg_dir = 0xc0002000
 #endif
-	
+
+	.section ".data.init"
 #include "../lib/hw_settings.S"
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c
--- v2.4.6/linux/arch/cris/kernel/irq.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/irq.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $
+/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $
  *
  *	linux/arch/cris/kernel/irq.c
  *
@@ -485,3 +485,10 @@
 #endif
 
 }
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
+/* Used by other archs to show/control IRQ steering during SMP */
+void init_irq_proc(void)
+{
+}
+#endif
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c
--- v2.4.6/linux/arch/cris/kernel/process.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/process.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $
+/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,9 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.14  2001/05/29 11:27:59  markusl
+ *  Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled
+ *
  *  Revision 1.13  2001/03/20 19:44:06  bjornw
  *  Use the 7th syscall argument for regs instead of current_regs
  *
@@ -90,12 +93,21 @@
 
 /* if the watchdog is enabled, we can simply disable interrupts and go
  * into an eternal loop, and the watchdog will reset the CPU after 0.1s
+ * if on the other hand the watchdog wasn't enabled, we just enable it and wait
  */
 
 void hard_reset_now (void)
 {
 	printk("*** HARD RESET ***\n");
 	cli();
+
+#ifndef CONFIG_ETRAX_WATCHDOG
+	/* Since we dont plan to keep on reseting the watchdog,
+	   the key can be arbitrary hence three */
+	*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) |
+		IO_STATE(R_WATCHDOG, enable, start);
+#endif
+
 	while(1) /* waiting for RETRIBUTION! */ ;
 }
 
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c
--- v2.4.6/linux/arch/cris/kernel/setup.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/setup.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $
+/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -190,14 +190,10 @@
 	unsigned short cache;
 	unsigned short flags;
 } cpu_info[] = {
+	/* The first four models will never ever run this code and are
+	   only here for display.  */
 	{ "ETRAX 1",   0, 0 },
-	{ "ETRAX 2",   0, 0 },	/* Don't say it HAS_TOKENRING - there are
-				   lethal bugs in that chip that
-				   prevents T-R from ever working.
-				   Never go there, and never lead anyone
-				   into believing it can work.  BTW:
-				   Anyone working on a T-R network
-				   driver? :-) :-) :-) :-/ */
+	{ "ETRAX 2",   0, 0 },
 	{ "ETRAX 3",   0, HAS_TOKENRING },
 	{ "ETRAX 4",   0, HAS_TOKENRING | HAS_SCSI },
 	{ "Unknown",   0, 0 },
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c
--- v2.4.6/linux/arch/cris/kernel/signal.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/signal.c	Wed Jul  4 11:50:39 2001
@@ -7,7 +7,7 @@
  *
  *  Ideas also taken from arch/arm.
  *
- *  Copyright (C) 2000 Axis Communications AB
+ *  Copyright (C) 2000, 2001 Axis Communications AB
  *
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
@@ -101,7 +101,14 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(0, &saveset, regs))
-			return -EINTR;
+			/* We will get here twice: once to call the signal
+			   handler, then again to return from the
+			   sigsuspend system call.  When calling the
+			   signal handler, R10 holds the signal number as
+			   set through do_signal.  The sigsuspend call
+			   will return with the restored value set above;
+			   always -EINTR.  */
+			return regs->r10;
 	}
 }
 
@@ -133,7 +140,14 @@
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(0, &saveset, regs))
-			return -EINTR;
+			/* We will get here twice: once to call the signal
+			   handler, then again to return from the
+			   sigsuspend system call.  When calling the
+			   signal handler, R10 holds the signal number as
+			   set through do_signal.  The sigsuspend call
+			   will return with the restored value set above;
+			   always -EINTR.  */
+			return regs->r10;
 	}
 }
 
@@ -413,6 +427,7 @@
 
 	regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
 	regs->srp = return_ip;                          /* what we enter LATER */
+	regs->r10 = sig;                                /* first argument is signo */
 
 	/* actually move the usp to reflect the stacked frame */
 
@@ -462,7 +477,6 @@
 		/* trampoline - the desired return ip is the retcode itself */
 		return_ip = (unsigned long)&frame->retcode;
 		/* This is movu.w __NR_sigreturn, r9; break 13; */
-		/* TODO: check byteorder */
 		err |= __put_user(0x9c5f,         (short *)(frame->retcode+0));
 		err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
 		err |= __put_user(0xe93d,         (short *)(frame->retcode+4));
@@ -477,6 +491,7 @@
 
 	regs->irp = (unsigned long) ka->sa.sa_handler;  /* what we enter NOW   */
 	regs->srp = return_ip;                          /* what we enter LATER */
+	regs->r10 = sig;                                /* first argument is signo */
 
 	/* actually move the usp to reflect the stacked frame */
 
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c
--- v2.4.6/linux/arch/cris/kernel/sys_cris.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/kernel/sys_cris.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $
+/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $
  *
  * linux/arch/cris/kernel/sys_cris.c
  *
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c
--- v2.4.6/linux/arch/cris/kernel/time.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/time.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.4 2000/10/17 14:44:58 bjornw Exp $
+/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
@@ -83,12 +83,9 @@
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
 	 * there are three kinds of problems that must be avoided here:
 	 *  1. the timer counter underflows
-	 *  2. hardware problem with the timer, not giving us continuous time,
-	 *     the counter does small "jumps" upwards on some Pentium systems,
-	 *     thus causes time warps
-	 *  3. we are after the timer interrupt, but the bottom half handler
+	 *  2. we are after the timer interrupt, but the bottom half handler
 	 *     hasn't executed yet.
-	 */
+ */
 	if( jiffies_t == jiffies_p ) {
 		if( count > count_p ) {
 		}
@@ -195,7 +192,7 @@
 	return retval;
 }
 
-/* Except from the Etrax100 HSDD about the built-in watchdog:
+/* Excerpt from the Etrax100 HSDD about the built-in watchdog:
  *
  * 3.10.4 Watchdog timer
 
@@ -231,14 +228,12 @@
 
 #define WATCHDOG_MIN_FREE_PAGES 8
 
-extern int nr_free_pages;
-
 static inline void
 reset_watchdog(void)
 {
 #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 	/* only keep watchdog happy as long as we have memory left! */
-	if(nr_free_pages > WATCHDOG_MIN_FREE_PAGES) {
+	if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
 		/* reset the watchdog with the inverse of the old key */
 		watchdog_key ^= 0x7; /* invert key, which is 3 bits */
 		*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c
--- v2.4.6/linux/arch/cris/kernel/traps.c	Sun May 20 12:11:38 2001
+++ linux/arch/cris/kernel/traps.c	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $
+/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $
  *
  *  linux/arch/cris/traps.c
  *
diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/checksum.S linux/arch/cris/lib/checksum.S
--- v2.4.6/linux/arch/cris/lib/checksum.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/lib/checksum.S	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: checksum.S,v 1.4 2001/02/19 11:11:33 bjornw Exp $
+/* $Id: checksum.S,v 1.5 2001/05/29 11:40:14 markusl Exp $
  * A fast checksum routine using movem
  * Copyright (c) 1998-2001 Axis Communications AB
  *
@@ -13,6 +13,8 @@
 	;; r12 - checksum
 
 	;; check for breakeven length between movem and normal word looping versions
+	;; we also do _NOT_ want to compute a checksum over more than the 
+	;; actual length when length < 40
 	
 	cmpu.w	80,r11
 	blo	word_loop
@@ -20,6 +22,8 @@
 
 	;; need to save the registers we use below in the movem loop
 	;; this overhead is why we have a check above for breakeven length
+	;; only r0 - r8 have to be saved, the other ones are clobber-able
+	;; according to the ABI
 	
 	subq	9*4,sp
 	movem	r8,[sp]
diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S
--- v2.4.6/linux/arch/cris/lib/checksumcopy.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/lib/checksumcopy.S	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: checksumcopy.S,v 1.4 2001/02/19 11:11:34 bjornw Exp $
+/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $
  * A fast checksum+copy routine using movem
  * Copyright (c) 1998, 2001 Axis Communications AB
  *
@@ -17,6 +17,8 @@
 	;; r13 - checksum
 
 	;; check for breakeven length between movem and normal word looping versions
+	;; we also do _NOT_ want to compute a checksum over more than the 
+	;; actual length when length < 40
 	
 	cmpu.w	80,r12
 	blo	word_loop
@@ -24,6 +26,8 @@
 
 	;; need to save the registers we use below in the movem loop
 	;; this overhead is why we have a check above for breakeven length
+	;; only r0 - r8 have to be saved, the other ones are clobber-able
+	;; according to the ABI
 	
 	subq	9*4,sp
 	movem	r8,[sp]
diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S
--- v2.4.6/linux/arch/cris/lib/dram_init.S	Tue May  1 16:04:56 2001
+++ linux/arch/cris/lib/dram_init.S	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $
+/* $Id: dram_init.S,v 1.8 2001/05/15 07:12:45 hp Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,9 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.8  2001/05/15 07:12:45  hp
+ * Copy warning from head.S about r8 and r9
+ *
  * Revision 1.7  2001/04/18 12:05:39  bjornw
  * Fixed comments, and explicitely include config.h to be sure its there
  *
@@ -44,6 +47,9 @@
 
 #include <linux/config.h>
 
+	;; WARNING! The registers r8 and r9 are used as parameters carrying
+	;; information from the decompressor (if the kernel was compressed). 
+	;; They should not be used in the code below.
 
 #ifndef CONFIG_SVINTO_SIM	
 	move.d   CONFIG_ETRAX_DEF_R_WAITSTATES, r0
diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/hw_settings.S linux/arch/cris/lib/hw_settings.S
--- v2.4.6/linux/arch/cris/lib/hw_settings.S	Sun May 20 12:11:38 2001
+++ linux/arch/cris/lib/hw_settings.S	Wed Jul  4 11:50:39 2001
@@ -1,14 +1,15 @@
-	;; $Id: hw_settings.S,v 1.2 2001/04/03 11:11:09 starvik Exp $
-	;; 
-	;; This table is used by some tools to extract hardware parameters.
-	;; The table should be included in the kernel and the decompressor.
-	;; Don't forget to update the tools if you change this table.
-	;;
-	;; Copyright (C) 2001 Axis Communications AB
-	;;
-	;; Authors:  Mikael Starvik (starvik@axis.com)	
+/*
+ * $Id: hw_settings.S,v 1.3 2001/04/21 17:02:46 bjornw Exp $
+ * 
+ * This table is used by some tools to extract hardware parameters.
+ * The table should be included in the kernel and the decompressor.
+ * Don't forget to update the tools if you change this table.
+ *
+ * Copyright (C) 2001 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik (starvik@axis.com)	
+ */
 
-	
 #define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \
 		(CONFIG_ETRAX_DEF_R_PORT_PA_DATA))
 #define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \
diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/usercopy.c linux/arch/cris/lib/usercopy.c
--- v2.4.6/linux/arch/cris/lib/usercopy.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/usercopy.c	Wed Jul  4 11:50:39 2001
@@ -273,20 +273,27 @@
 	movem	r10,[r13+]
 
 	addq   44,r12  ;; compensate for last loop underflowing n
-
+8:
 	;; Restore registers from stack
 	movem [sp+],r10
 
 	.section .fixup,\"ax\"
 
-; To provide a correct count in r10 of bytes that failed to be copied,
-; we jump back into the loop if the loop-branch was taken.
-;  There is no performance penalty; the program will segfault soon
-; enough.
+;; Do not jump back into the loop if we fail.  For some uses, we get a
+;; page fault but for performance reasons we care to not get further
+;; faults.  For example, fs/super.c at one time did
+;;  i = size - copy_from_user((void *)page, data, size);
+;; which would cause repeated faults while clearing the remainder of
+;; the SIZE bytes at PAGE after the first fault.
 
 3:
 	move.d [sp],r10
+
+;; Number of remaining bytes, cleared but not copied, is r12 + 44.
+
+	add.d r12,r10
 	addq 44,r10
+
 	move.d r10,[sp]
 	clear.d r0
 	clear.d r1
@@ -299,7 +306,40 @@
 	clear.d r8
 	clear.d r9
 	clear.d r10
-	jump 1b
+
+;; Perform clear similar to the copy-loop.
+
+4:
+	subq 44,r12
+	bge 4b
+	movem r10,[r13+]
+
+;; Clear by four for the remaining multiples.
+
+	addq 40,r12
+	bmi 6f
+	nop
+5:
+	subq 4,r12
+	bpl 5b
+	clear.d [r13+]
+6:
+	addq 4,r12
+	beq 7f
+	nop
+
+	subq 1,r12
+	beq 7f
+	clear.b [r13+]
+
+	subq 1,r12
+	beq 7f
+	clear.b [r13+]
+
+	clear.d r12
+	clear.b [r13+]
+7:
+	jump 8b
 
 	.previous
 	.section __ex_table,\"a\"
diff -u --recursive --new-file v2.4.6/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c
--- v2.4.6/linux/arch/cris/mm/fault.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/mm/fault.c	Wed Jul  4 11:50:39 2001
@@ -6,6 +6,19 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.16  2001/06/13 00:06:08  bjornw
+ *  current_pgd should be volatile
+ *
+ *  Revision 1.15  2001/06/13 00:02:23  bjornw
+ *  Use a separate variable to store the current pgd to avoid races in schedule
+ *
+ *  Revision 1.14  2001/05/16 17:41:07  hp
+ *  Last comment tweak further tweaked.
+ *
+ *  Revision 1.13  2001/05/15 00:58:44  hp
+ *  Expand a bit on the comment why we compare address >= TASK_SIZE rather
+ *  than >= VMALLOC_START.
+ *
  *  Revision 1.12  2001/04/04 10:51:14  bjornw
  *  mmap_sem is grabbed for reading
  *
@@ -59,6 +72,10 @@
 /* debug of higher-level faults */
 #define DPG(x)
 
+/* current active page directory */
+
+volatile pgd_t *current_pgd;
+
 /* fast TLB-fill fault handler */
 
 void
@@ -94,9 +111,11 @@
 
 	if(miss) {
 
-		/* see if the pte exists at all */
+		/* see if the pte exists at all
+		 * refer through current_pgd, dont use mm->pgd
+		 */
 		
-		pmd = (pmd_t *)pgd_offset(mm, address);
+		pmd = (pmd_t *)(current_pgd + pgd_index(address));
 		if(pmd_none(*pmd))
 			goto dofault;
 		if(pmd_bad(*pmd)) {
@@ -206,7 +225,9 @@
 	 * should really be >= VMALLOC_START, however, kernel fixup errors
 	 * will be handled more quickly by going through vmalloc_fault and then
 	 * into bad_area_nosemaphore than falling through the find_vma user-mode
-	 * tests.
+	 * tests.  As an aside can be mentioned that the difference in
+	 * compiled code is neglibible; the instruction is the same, just a
+	 * comparison with a different address of the same size.
          */
 
         if (address >= TASK_SIZE)
@@ -384,12 +405,17 @@
                 /*
                  * Synchronize this task's top level page-table
                  * with the 'reference' page table.
+		 *
+		 * Use current_pgd instead of tsk->active_mm->pgd
+		 * since the latter might be unavailable if this
+		 * code is executed in a misfortunately run irq
                  */
+
                 int offset = pgd_index(address);
                 pgd_t *pgd, *pgd_k;
                 pmd_t *pmd, *pmd_k;
 
-                pgd = tsk->active_mm->pgd + offset;
+                pgd = current_pgd + offset;
                 pgd_k = init_mm.pgd + offset;
 
                 if (!pgd_present(*pgd)) {
diff -u --recursive --new-file v2.4.6/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c
--- v2.4.6/linux/arch/cris/mm/init.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/mm/init.c	Wed Jul  4 11:50:39 2001
@@ -7,6 +7,12 @@
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.25  2001/06/13 00:02:23  bjornw
+ *  Use a separate variable to store the current pgd to avoid races in schedule
+ *
+ *  Revision 1.24  2001/05/15 00:52:20  hp
+ *  Only map segment 0xa as seg if CONFIG_JULIETTE
+ *
  *  Revision 1.23  2001/04/04 14:35:40  bjornw
  *  * Removed get_pte_slow and friends (2.4.3 change)
  *  * Removed bad_pmd handling (2.4.3 change)
@@ -85,6 +91,7 @@
 #include <asm/dma.h>
 #include <asm/svinto.h>
 #include <asm/io.h>
+#include <asm/mmu_context.h>
 
 static unsigned long totalram_pages;
 
@@ -177,6 +184,13 @@
 
 	for(i = 0; i < PTRS_PER_PGD; i++)
 		swapper_pg_dir[i] = __pgd(0);
+	
+	/* make sure the current pgd table points to something sane
+	 * (even if it is most probably not used until the next 
+	 *  switch_mm)
+	 */
+
+	current_pgd = init_mm.pgd;
 
 	/* initialise the TLB (tlb.c) */
 
@@ -241,7 +255,11 @@
 			IO_STATE(R_MMU_KSEG, seg_d, page ) | 
 			IO_STATE(R_MMU_KSEG, seg_c, page ) |   
 			IO_STATE(R_MMU_KSEG, seg_b, seg  ) |  /* kernel reg area */
+#ifdef CONFIG_JULIETTE
 			IO_STATE(R_MMU_KSEG, seg_a, seg  ) |  /* ARTPEC etc. */
+#else
+			IO_STATE(R_MMU_KSEG, seg_a, page ) |
+#endif
 			IO_STATE(R_MMU_KSEG, seg_9, seg  ) |  /* LED's on some boards */
 			IO_STATE(R_MMU_KSEG, seg_8, seg  ) |  /* CSE0/1, flash and I/O */
 			IO_STATE(R_MMU_KSEG, seg_7, page ) |  /* kernel vmalloc area */
@@ -258,7 +276,11 @@
 			    IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
+#ifdef CONFIG_JULIETTE
 			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) |
+#else
+			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) |
+#endif
 			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) |
 			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) );
 	
@@ -442,7 +464,7 @@
 
 	i = max_mapnr;
 	val->totalram = 0;
-	val->sharedram = 0;
+	val->sharedram = atomic_read(&shmem_nrpages);
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
 	while (i-- > 0)  {
diff -u --recursive --new-file v2.4.6/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c
--- v2.4.6/linux/arch/cris/mm/tlb.c	Tue May  1 16:04:56 2001
+++ linux/arch/cris/mm/tlb.c	Wed Jul  4 11:50:39 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/cris/mm/tlb.c
  *
- *  Copyright (C) 2000  Axis Communications AB
+ *  Copyright (C) 2000, 2001  Axis Communications AB
  *  
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
@@ -21,6 +21,7 @@
 #include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/svinto.h>
+#include <asm/mmu_context.h>
 
 #define D(x)
 
@@ -252,6 +253,15 @@
 
 	get_mmu_context(next);
 
+	/* remember the pgd for the fault handlers
+	 * this is similar to the pgd register in some other CPU's.
+	 * we need our own copy of it because current and active_mm
+	 * might be invalid at points where we still need to derefer
+	 * the pgd.
+	 */
+
+	current_pgd = next->pgd;
+
 	/* switch context in the MMU */
 	
 	D(printk("switching mmu_context to %d (%p)\n", next->context, next));
@@ -288,7 +298,7 @@
 
 	/* clear the page_id map */
 
-	for(i = 0; i < NUM_PAGEID; i++)
+	for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++)
 		page_id_map[i] = NULL;
 	
 	/* invalidate the entire TLB */
diff -u --recursive --new-file v2.4.6/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v2.4.6/linux/arch/i386/boot/video.S	Sun Nov 21 00:09:51 1999
+++ linux/arch/i386/boot/video.S	Thu Jul  5 11:28:16 2001
@@ -496,7 +496,7 @@
 	jnc	setbad
 	
 	addw	%bx, %bx
-	.word	0xa7ff, spec_inits		# JMP [BX+spec_inits]
+	jmp	*spec_inits(%bx)
 
 setmenu:
 	orb	%al, %al			# 80x25 is an exception
@@ -1008,7 +1008,7 @@
 vesa1:
 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
 # XXX:	lodsw	%gs:(%si), %ax			# Get next mode in the list
-	.byte	0x65, 0xAD			# %gs seg prefix + lodsw
+	gs; lodsw
 	cmpw	$0xffff, %ax			# End of the table?
 	jz	vesar
 	
diff -u --recursive --new-file v2.4.6/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.6/linux/arch/i386/defconfig	Tue Jul  3 17:08:18 2001
+++ linux/arch/i386/defconfig	Sat Jul  7 11:42:49 2001
@@ -414,6 +414,7 @@
 #
 # CONFIG_ACENIC is not set
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
--- v2.4.6/linux/arch/i386/kernel/dmi_scan.c	Tue Feb 13 14:13:43 2001
+++ linux/arch/i386/kernel/dmi_scan.c	Wed Jul  4 14:41:33 2001
@@ -1,8 +1,10 @@
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/apm_bios.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 
 struct dmi_header
@@ -13,6 +15,7 @@
 };
 
 #define dmi_printk(x)
+//#define dmi_printk(x) printk(x)
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
@@ -90,9 +93,254 @@
 }
 
 
+enum
+{
+	DMI_BIOS_VENDOR,
+	DMI_BIOS_VERSION,
+	DMI_BIOS_DATE,
+	DMI_SYS_VENDOR,
+	DMI_PRODUCT_NAME,
+	DMI_PRODUCT_VERSION,
+	DMI_BOARD_VENDOR,
+	DMI_BOARD_NAME,
+	DMI_BOARD_VERSION,
+	DMI_STRING_MAX
+};
+
+static char *dmi_ident[DMI_STRING_MAX];
+
+/*
+ *	Save a DMI string
+ */
+ 
+static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
+{
+	char *d = (char*)dm;
+	char *p = dmi_string(dm, d[string]);
+	if(p==NULL || *p == 0)
+		return;
+	if (dmi_ident[slot])
+		return;
+	dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL);
+	if(dmi_ident[slot])
+		strcpy(dmi_ident[slot], p);
+	else
+		printk(KERN_ERR "dmi_save_ident: out of memory.\n");
+}
+
+/*
+ *	DMI callbacks for problem boards
+ */
+
+struct dmi_strmatch
+{
+	u8 slot;
+	char *substr;
+};
+
+#define NONE	255
+
+struct dmi_blacklist
+{
+	int (*callback)(struct dmi_blacklist *);
+	char *ident;
+	struct dmi_strmatch matches[4];
+};
+
+#define NO_MATCH	{ NONE, NULL}
+#define MATCH(a,b)	{ a, b }
+
+/*
+ *	We have problems with IDE DMA on some platforms. In paticular the
+ *	KT7 series. On these it seems the newer BIOS has fixed them. The
+ *	rule needs to be improved to match specific BIOS revisions with
+ *	corruption problems
+ */ 
+ 
+static __init int disable_ide_dma(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_BLK_DEV_IDE
+	extern int noautodma;
+	if(noautodma == 0)
+	{
+		noautodma = 1;
+		printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident);
+	}
+#endif	
+	return 0;
+}
+
+/* 
+ * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
+ */
+static __init int set_bios_reboot(struct dmi_blacklist *d)
+{
+	extern int reboot_thru_bios;
+	if (reboot_thru_bios == 0)
+	{
+		reboot_thru_bios = 1;
+		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
+	}
+	return 0;
+}
+
+/*
+ * Some bioses have a broken protected mode poweroff and need to use realmode
+ */
+
+static __init int set_realmode_power_off(struct dmi_blacklist *d)
+{
+       if (apm_info.realmode_power_off == 0)
+       {
+               apm_info.realmode_power_off = 1;
+               printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident);
+       }
+       return 0;
+}
+
+
+/* 
+ * Some laptops require interrupts to be enabled during APM calls 
+ */
+
+static __init int set_apm_ints(struct dmi_blacklist *d)
+{
+	if (apm_info.allow_ints == 0)
+	{
+		apm_info.allow_ints = 1;
+		printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident);
+	}
+	return 0;
+}
+
+/* 
+ * Some APM bioses corrupt memory or just plain do not work
+ */
+
+static __init int apm_is_horked(struct dmi_blacklist *d)
+{
+	if (apm_info.disabled == 0)
+	{
+		apm_info.disabled = 1;
+		printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
+	}
+	return 0;
+}
+
+
+/*
+ *  Check for clue free BIOS implementations who use
+ *  the following QA technique
+ *
+ *      [ Write BIOS Code ]<------
+ *               |                ^
+ *      < Does it Compile >----N--
+ *               |Y               ^
+ *	< Does it Boot Win98 >-N--
+ *               |Y
+ *           [Ship It]
+ *
+ *	Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
+ *	Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
+ */
+
+static __init int broken_apm_power(struct dmi_blacklist *d)
+{
+	apm_info.get_power_status_broken = 1;
+	printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
+	return 0;
+}		
+
+/*
+ *	Process the DMI blacklists
+ */
+ 
+
+/*
+ *	This will be expanded over time to force things like the APM 
+ *	interrupt mask settings according to the laptop
+ */
+ 
+static __initdata struct dmi_blacklist dmi_blacklist[]={
+#if 0
+	{ disable_ide_dma, "KT7", {	/* Overbroad right now - kill DMA on problem KT7 boards */
+			MATCH(DMI_PRODUCT_NAME, "KT7-RAID"),
+			NO_MATCH, NO_MATCH, NO_MATCH
+			} },
+#endif			
+	{ broken_apm_power, "Dell Inspiron 5000e", {	/* Handle problems with APM on Inspiron 5000e */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "A04"),
+			MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH
+			} },
+	{ set_realmode_power_off, "Award Software v4.60 PGMA", {	/* broken PM poweroff bios */
+			MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
+			MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
+			MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
+			} },
+	{ set_bios_reboot, "PowerEdge 1300/500", {	/* Handle problems with rebooting on Dell 1300's */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/500"),
+			NO_MATCH, NO_MATCH
+			} },
+	{ set_bios_reboot, "PowerEdge 1300/550", {	/* Handle problems with rebooting on Dell 1300's */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/550"),
+			NO_MATCH, NO_MATCH
+			} },
+	{ set_apm_ints, "IBM", {	/* Allow interrupts during suspend on IBM laptops */
+			MATCH(DMI_SYS_VENDOR, "IBM"),
+			NO_MATCH, NO_MATCH, NO_MATCH
+			} },
+	{ set_apm_ints, "ASUSTeK", {   /* Allow interrupts during APM or the clock goes slow */
+			MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"),
+			NO_MATCH, NO_MATCH
+			} },					
+	{ apm_is_horked, "Trigem Delhi3", { /* APM crashes */
+			MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
+			MATCH(DMI_PRODUCT_NAME, "Delhi3"),
+			NO_MATCH, NO_MATCH,
+			} },
+	{ NULL, }
+};
+	
+	
+/*
+ *	Walk the blacklist table running matching functions until someone 
+ *	returns 1 or we hit the end.
+ */
+ 
+static __init void dmi_check_blacklist(void)
+{
+	struct dmi_blacklist *d;
+	int i;
+		
+	d=&dmi_blacklist[0];
+	while(d->callback)
+	{
+		for(i=0;i<4;i++)
+		{
+			int s = d->matches[i].slot;
+			if(s==NONE)
+				continue;
+			if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
+				continue;
+			/* No match */
+			goto fail;
+		}
+		if(d->callback(d))
+			return;
+fail:			
+		d++;
+	}
+}
+
+	
+
 /*
  *	Process a DMI table entry. Right now all we care about are the BIOS
- *	and machine entries. For 2.4 we should pull the smbus controller info
+ *	and machine entries. For 2.5 we should pull the smbus controller info
  *	out of here.
  */
 
@@ -105,66 +353,47 @@
 	{
 		case  0:
 			p=dmi_string(dm,data[4]);
-
-			if(*p && *p!=' ')
+			if(*p)
 			{
 				dmi_printk(("BIOS Vendor: %s\n", p));
+				dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
 				dmi_printk(("BIOS Version: %s\n", 
 					dmi_string(dm, data[5])));
+				dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
 				dmi_printk(("BIOS Release: %s\n",
 					dmi_string(dm, data[8])));
-			}
-				
-			/*
-			 *  Check for clue free BIOS implementations who use
-			 *  the following QA technique
-			 *
-			 *      [ Write BIOS Code ]<------
-			 *               |                ^
-			 *      < Does it Compile >----N--
-			 *               |Y               ^
-			 *	< Does it Boot Win98 >-N--
-			 *               |Y
-			 *           [Ship It]
-			 *
-			 *	Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
-			 *	Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
-			 */
-			 
-			if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0)
-			{
-				if(strcmp(dmi_string(dm, data[5]), "A04")==0 
-					&& strcmp(dmi_string(dm, data[8]), "08/24/2000")==0)
-				{
-				   	apm_info.get_power_status_broken = 1;
-					printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
-				}
+				dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			}
 			break;
+			
 		case 1:
 			p=dmi_string(dm,data[4]);
-
-			if(*p && *p!=' ')
+			if(*p)
 			{
 				dmi_printk(("System Vendor: %s.\n",p));
+				dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
 				dmi_printk(("Product Name: %s.\n",
 					dmi_string(dm, data[5])));
+				dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
 				dmi_printk(("Version %s.\n",
 					dmi_string(dm, data[6])));
+				dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
 				dmi_printk(("Serial Number %s.\n",
 					dmi_string(dm, data[7])));
 			}
 			break;
 		case 2:
 			p=dmi_string(dm,data[4]);
-
-			if(*p && *p!=' ')
+			if(*p)
 			{
 				dmi_printk(("Board Vendor: %s.\n",p));
+				dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
 				dmi_printk(("Board Name: %s.\n",
 					dmi_string(dm, data[5])));
+				dmi_save_ident(dm, DMI_BOARD_NAME, 5);
 				dmi_printk(("Board Version: %s.\n",
 					dmi_string(dm, data[6])));
+				dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
 			}
 			break;
 		case 3:
@@ -177,7 +406,10 @@
 
 static int __init dmi_scan_machine(void)
 {
-	return dmi_iterate(dmi_decode);
+	int err = dmi_iterate(dmi_decode);
+	if(err == 0)
+		dmi_check_blacklist();
+	return err;
 }
 
 module_init(dmi_scan_machine);
diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- v2.4.6/linux/arch/i386/kernel/pci-irq.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/i386/kernel/pci-irq.c	Wed Jul  4 15:39:28 2001
@@ -391,6 +391,38 @@
 	return 1;
 }
 
+/* Support for AMD756 PCI IRQ Routing
+ * Jhon H. Caicedo <jhcaiced@osso.org.co>
+ * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
+ * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
+ * The AMD756 pirq rules are nibble-based
+ * offset 0x56 0-3 PIRQA  4-7  PIRQB
+ * offset 0x57 0-3 PIRQC  4-7  PIRQD
+ */
+static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 irq;
+	irq = 0;
+	if (pirq <= 4)
+	{
+		irq = read_config_nybble(router, 0x56, pirq - 1);
+	}
+	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
+		dev->vendor, dev->device, pirq, irq);
+	return irq;
+}
+
+static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
+		dev->vendor, dev->device, pirq, irq);
+	if (pirq <= 4)
+	{
+		write_config_nybble(router, 0x56, pirq - 1, irq);
+	}
+	return 1;
+}
+
 #ifdef CONFIG_PCI_BIOS
 
 static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -426,6 +458,8 @@
 	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
 	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
 	  pirq_serverworks_get, pirq_serverworks_set },
+	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
+		pirq_amd756_get, pirq_amd756_set },
 
 	{ "default", 0, 0, NULL, NULL }
 };
diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.4.6/linux/arch/i386/kernel/process.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/i386/kernel/process.c	Wed Jul  4 14:41:33 2001
@@ -152,7 +152,7 @@
 
 static long no_idt[2];
 static int reboot_mode;
-static int reboot_thru_bios;
+int reboot_thru_bios;
 
 static int __init reboot_setup(char *str)
 {
diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.4.6/linux/arch/i386/kernel/setup.c	Fri May 25 17:07:09 2001
+++ linux/arch/i386/kernel/setup.c	Thu Jul  5 11:42:38 2001
@@ -1123,7 +1123,6 @@
 static int __init init_amd(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
-	unsigned long flags;
 	int mbytes = max_mapnr >> (20-PAGE_SHIFT);
 	int r;
 
@@ -1187,14 +1186,13 @@
 					mbytes=508;
 					
 				rdmsr(0xC0000082, l, h);
-				if((l&0x0000FFFF)==0)
-				{		
+				if ((l&0x0000FFFF)==0) {
+					unsigned long flags;
 					l=(1<<0)|((mbytes/4)<<1);
-					save_flags(flags);
-					__cli();
+					local_irq_save(flags);
 					__asm__ __volatile__ ("wbinvd": : :"memory");
 					wrmsr(0xC0000082, l, h);
-					restore_flags(flags);
+					local_irq_restore(flags);
 					printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
 						mbytes);
 					
@@ -1209,14 +1207,13 @@
 					mbytes=4092;
 
 				rdmsr(0xC0000082, l, h);
-				if((l&0xFFFF0000)==0)
-				{
+				if ((l&0xFFFF0000)==0) {
+					unsigned long flags;
 					l=((mbytes>>2)<<22)|(1<<16);
-					save_flags(flags);
-					__cli();
+					local_irq_save(flags);
 					__asm__ __volatile__ ("wbinvd": : :"memory");
 					wrmsr(0xC0000082, l, h);
-					restore_flags(flags);
+					local_irq_restore(flags);
 					printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
 						mbytes);
 				}
@@ -1243,12 +1240,13 @@
 /*
  * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
-static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+static void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
 {
 	unsigned char ccr2, ccr3;
+	unsigned long flags;
 
 	/* we test for DEVID by checking whether CCR3 is writable */
-	cli();
+	local_irq_save(flags);
 	ccr3 = getCx86(CX86_CCR3);
 	setCx86(CX86_CCR3, ccr3 ^ 0x80);
 	getCx86(0xc0);   /* dummy to change bus */
@@ -1272,7 +1270,7 @@
 		*dir0 = getCx86(CX86_DIR0);
 		*dir1 = getCx86(CX86_DIR1);
 	}
-	sti();
+	local_irq_restore(flags);
 }
 
 /*
@@ -1316,15 +1314,16 @@
 {
 	if (Cx86_dir0_msb == 3) {
 		unsigned char ccr3, ccr5;
+		unsigned long flags;
 
-		cli();
+		local_irq_save(flags);
 		ccr3 = getCx86(CX86_CCR3);
 		setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
 		ccr5 = getCx86(CX86_CCR5);
 		if (ccr5 & 2)
 			setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
 		setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-		sti();
+		local_irq_restore(flags);
 
 		if (ccr5 & 2) { /* possible wrong calibration done */
 			printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
@@ -1438,8 +1437,16 @@
 		break;
 
         case 5: /* 6x86MX/M II */
-		if (dir1 > 7) dir0_msn++;  /* M II */
-		else c->coma_bug = 1;      /* 6x86MX, it has the bug. */
+		if (dir1 > 7)
+		{
+			dir0_msn++;  /* M II */
+			/* Enable MMX extensions (App note 108) */
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
+		}
+		else
+		{
+			c->coma_bug = 1;      /* 6x86MX, it has the bug. */
+		}
 		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
 		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
 		p = Cx86_cb+tmp;
@@ -2092,15 +2099,16 @@
    	        if (dir0 == 5 || dir0 == 3)
    	        {
 			unsigned char ccr3, ccr4;
+			unsigned long flags;
 
 			printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
-			cli();
+			local_irq_save(flags);
 			ccr3 = getCx86(CX86_CCR3);
 			setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
 			ccr4 = getCx86(CX86_CCR4);
 			setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
 			setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-			sti();
+			local_irq_restore(flags);
 		}
 	} else
 
diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.4.6/linux/arch/i386/kernel/signal.c	Tue Feb 13 13:15:04 2001
+++ linux/arch/i386/kernel/signal.c	Wed Jul  4 14:41:33 2001
@@ -370,7 +370,7 @@
 
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (! on_sig_stack(esp))
+		if (sas_ss_flags(esp) == 0)
 			esp = current->sas_ss_sp + current->sas_ss_size;
 	}
 
diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.4.6/linux/arch/i386/kernel/vm86.c	Sun Oct  1 20:35:15 2000
+++ linux/arch/i386/kernel/vm86.c	Fri Jul  6 17:05:07 2001
@@ -456,7 +456,7 @@
 	if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \
 		pushw(ssp,sp,popw(ssp,sp) | TF_MASK);
 #define VM86_FAULT_RETURN \
-	if (VMPI.force_return_for_pic  && (VEFLAGS & IF_MASK)) \
+	if (VMPI.force_return_for_pic  && (VEFLAGS & (IF_MASK | VIF_MASK))) \
 		return_to_32bit(regs, VM86_PICRETURN); \
 	return;
 	                                   
diff -u --recursive --new-file v2.4.6/linux/arch/i386/math-emu/reg_u_div.S linux/arch/i386/math-emu/reg_u_div.S
--- v2.4.6/linux/arch/i386/math-emu/reg_u_div.S	Fri Apr  6 10:42:47 2001
+++ linux/arch/i386/math-emu/reg_u_div.S	Wed Jul  4 14:41:33 2001
@@ -89,10 +89,8 @@
 	movl	REGB,%ebx
 	movl	DEST,%edi
 
-	movw	EXP(%esi),%dx
-	movw	EXP(%ebx),%ax
-	.byte	0x0f,0xbf,0xc0	/* movsx	%ax,%eax */
-	.byte	0x0f,0xbf,0xd2	/* movsx	%dx,%edx */
+	movswl	EXP(%esi),%edx
+	movswl	EXP(%ebx),%eax
 	subl	%eax,%edx
 	addl	EXP_BIAS,%edx
 
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c
--- v2.4.6/linux/arch/mips/mm/andes.c	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/mm/andes.c	Wed Jul  4 11:50:39 2001
@@ -119,6 +119,17 @@
 	/* XXX */
 }
 
+static void __andes_flush_icache_range(unsigned long start, unsigned long end)
+{
+	/* XXX */
+}
+
+static void andes_flush_icache_page(struct vm_area_struct *vma,
+                                    struct page *page)
+{
+	/* XXX */
+}
+
 static void andes_flush_cache_sigtramp(unsigned long page)
 {
 	/* XXX */
@@ -146,10 +157,6 @@
 	/* XXX */
 }
 
-void load_pgd(unsigned long pg_dir)
-{
-}
-
 void pgd_init(unsigned long page)
 {
 }
@@ -166,11 +173,14 @@
 	_copy_page = andes_copy_page;
 
 	_flush_cache_all = andes_flush_cache_all;
+	___flush_cache_all = andes_flush_cache_all;
 	_flush_cache_mm = andes_flush_cache_mm;
 	_flush_cache_range = andes_flush_cache_range;
 	_flush_cache_page = andes_flush_cache_page;
 	_flush_cache_sigtramp = andes_flush_cache_sigtramp;
 	_flush_page_to_ram = andes_flush_page_to_ram;
+	_flush_icache_page = andes_flush_icache_page;
+	_flush_icache_range = andes_flush_icache_range;
 
 	flush_cache_all();
 	flush_tlb_all();
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/extable.c linux/arch/mips/mm/extable.c
--- v2.4.6/linux/arch/mips/mm/extable.c	Thu Feb 24 22:52:30 2000
+++ linux/arch/mips/mm/extable.c	Wed Jul  4 11:50:39 2001
@@ -3,6 +3,7 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 extern const struct exception_table_entry __start___ex_table[];
@@ -29,26 +30,33 @@
 	return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
-
+	unsigned long ret = 0;
+	
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return ret;
+	return ret;
 #else
+	unsigned long flags;
+
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
-		if (ret) return ret;
+		if (ret)
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.4.6/linux/arch/mips/mm/fault.c	Mon Mar 19 12:35:09 2001
+++ linux/arch/mips/mm/fault.c	Wed Jul  4 11:50:39 2001
@@ -49,6 +49,18 @@
 	unsigned long fixup;
 	siginfo_t info;
 
+	/*
+	 * We fault-in kernel-space virtual memory on-demand. The
+	 * 'reference' page table is init_mm.pgd.
+	 *
+	 * NOTE! We MUST NOT take any locks for this case. We may
+	 * be in an interrupt or a critical region, and should
+	 * only copy the information from the master page table,
+	 * nothing more.
+	 */
+	if (address >= TASK_SIZE)
+		goto vmalloc_fault;
+
 	info.si_code = SEGV_MAPERR;
 	/*
 	 * If we're in an interrupt or have no user
@@ -113,6 +125,8 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
+bad_area_nosemaphore:
+	/* User mode accesses just cause a SIGSEGV */
 	if (user_mode(regs)) {
 		tsk->thread.cp0_badvaddr = address;
 		tsk->thread.error_code = write;
@@ -186,4 +200,34 @@
 	/* Kernel mode? Handle exceptions or die */
 	if (!user_mode(regs))
 		goto no_context;
+
+	return;
+
+vmalloc_fault:
+	{
+		/*
+		 * Synchronize this task's top level page-table
+		 * with the 'reference' page table.
+		 */
+		int offset = pgd_index(address);
+		pgd_t *pgd, *pgd_k;
+		pmd_t *pmd, *pmd_k;
+
+		pgd = tsk->active_mm->pgd + offset;
+		pgd_k = init_mm.pgd + offset;
+
+		if (!pgd_present(*pgd)) {
+			if (!pgd_present(*pgd_k))
+				goto bad_area_nosemaphore;
+			set_pgd(pgd, *pgd_k);
+			return;
+		}
+
+		pmd = pmd_offset(pgd, address);
+		pmd_k = pmd_offset(pgd_k, address);
+
+		if (pmd_present(*pmd) || !pmd_present(*pmd_k))
+			goto bad_area_nosemaphore;
+		set_pmd(pmd, *pmd_k);
+	}
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.4.6/linux/arch/mips/mm/init.c	Mon Oct 16 12:58:51 2000
+++ linux/arch/mips/mm/init.c	Wed Jul  4 11:50:39 2001
@@ -1,11 +1,13 @@
-/* $Id: init.c,v 1.26 2000/02/23 00:41:00 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Copyright (C) 1994 - 2000 by Ralf Baechle
  * Copyright (C) 2000 Silicon Graphics, Inc.
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -29,6 +31,7 @@
 
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
+#include <asm/cpu.h>
 #include <asm/dma.h>
 #include <asm/jazzdma.h>
 #include <asm/system.h>
@@ -38,74 +41,20 @@
 #include <asm/sgialib.h>
 #endif
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
-extern void prom_fixup_mem_map(unsigned long start, unsigned long end);
 extern void prom_free_prom_memory(void);
 
 
-void __bad_pte_kernel(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, BAD_PAGETABLE);
-}
-
-void __bad_pte(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, BAD_PAGETABLE);
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *page;
-
-	page = (pte_t *) __get_free_page(GFP_USER);
-	if (pmd_none(*pmd)) {
-		if (page) {
-			clear_page(page);
-			pmd_val(*pmd) = (unsigned long)page;
-			return page + offset;
-		}
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)page);
-	if (pmd_bad(*pmd)) {
-		__bad_pte_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *page;
-
-	page = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (page) {
-			clear_page(page);
-			pmd_val(*pmd) = (unsigned long)page;
-			return page + offset;
-		}
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)page);
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-
 asmlinkage int sys_cacheflush(void *addr, int bytes, int cache)
 {
-	/* XXX Just get it working for now... */
-	flush_cache_all();
+	/* This should flush more selectivly ...  */
+	__flush_cache_all();
+
 	return 0;
 }
 
@@ -122,17 +71,10 @@
 {
 	unsigned long order, size;
 	struct page *page;
-
-	switch (mips_cputype) {
-	case CPU_R4000SC:
-	case CPU_R4000MC:
-	case CPU_R4400SC:
-	case CPU_R4400MC:
+	if(mips_cpu.options & MIPS_CPU_VCE) 
 		order = 3;
-		break;
-	default:
+	else 
 		order = 0;
-	}
 
 	empty_zero_page = __get_free_pages(GFP_KERNEL, order);
 	if (!empty_zero_page)
@@ -169,48 +111,6 @@
 	return freed;
 }
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-pte_t * __bad_pagetable(void)
-{
-	extern char empty_bad_page_table[PAGE_SIZE];
-	unsigned long page, dummy1, dummy2;
-
-	page = (unsigned long) empty_bad_page_table;
-	__asm__ __volatile__(
-		".set\tnoreorder\n"
-		"1:\tsw\t%2,(%0)\n\t"
-		"subu\t%1,1\n\t"
-		"bnez\t%1,1b\n\t"
-		"addiu\t%0,4\n\t"
-		".set\treorder"
-		:"=r" (dummy1), "=r" (dummy2)
-		:"r" (pte_val(BAD_PAGE)), "0" (page), "1" (PAGE_SIZE/4)
-		:"$1");
-
-	return (pte_t *)page;
-}
-
-pte_t __bad_page(void)
-{
-	extern char empty_bad_page[PAGE_SIZE];
-	unsigned long page = (unsigned long) empty_bad_page;
-
-	clear_page((void *)page);
-	return pte_mkdirty(mk_pte_phys(__pa(page), PAGE_SHARED));
-}
-
 void show_mem(void)
 {
 	int i, free = 0, total = 0, reserved = 0;
@@ -271,7 +171,30 @@
 	free_area_init(zones_size);
 }
 
-extern int page_is_ram(unsigned long pagenr);
+#define PFN_UP(x)	(((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+
+static inline int page_is_ram(unsigned long pagenr)
+{
+	int i;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long addr, end;
+
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			/* not usable memory */
+			continue;
+
+		addr = PFN_UP(boot_mem_map.map[i].addr);
+		end = PFN_DOWN(boot_mem_map.map[i].addr
+			       + boot_mem_map.map[i].size);
+
+		if (pagenr >= addr && pagenr < end)
+			return 1;
+	}
+
+	return 0;
+}
 
 void __init mem_init(void)
 {
@@ -309,13 +232,16 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
+	if (start < end)
+		printk("Freeing initrd memory: %ldk freed\n",
+		       (end - start) >> 10);
+
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
 		set_page_count(virt_to_page(start), 1);
 		free_page(start);
 		totalram_pages++;
 	}
-	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 }
 #endif
 
@@ -343,7 +269,7 @@
 void si_meminfo(struct sysinfo *val)
 {
 	val->totalram = totalram_pages;
-	val->sharedram = 0;
+	val->sharedram = atomic_read(&shmem_nrpages);
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
 	val->totalhigh = 0;
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/ioremap.c linux/arch/mips/mm/ioremap.c
--- v2.4.6/linux/arch/mips/mm/ioremap.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mm/ioremap.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,176 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ * (C) Copyright 2001 Ralf Baechle
+ */
+#include <linux/module.h>
+#include <asm/addrspace.h>
+#include <asm/byteorder.h>
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+	pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
+	                           | __WRITEABLE | flags);
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, mk_pte_phys(phys_addr, pgprot));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	int error;
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			break;
+		error = 0;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
+	flush_tlb_all();
+	return error;
+}
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+
+#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL))
+
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+	void * addr;
+	struct vm_struct * area;
+	unsigned long offset, last_addr;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
+
+	/*
+	 * Map objects in the low 512mb of address space using KSEG1, otherwise
+	 * map using page tables.
+	 */
+	if (IS_LOW512(phys_addr) && IS_LOW512(phys_addr + size - 1))
+		return (void *) KSEG1ADDR(phys_addr);
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using..
+	 */
+	if (phys_addr < virt_to_phys(high_memory)) {
+		char *t_addr, *t_end;
+		struct page *page;
+
+		t_addr = __va(phys_addr);
+		t_end = t_addr + (size - 1);
+	   
+		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
+			if(!PageReserved(page))
+				return NULL;
+	}
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
+
+	/*
+	 * Ok, go for it..
+	 */
+	area = get_vm_area(size, VM_IOREMAP);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+
+	return (void *) (offset + (char *)addr);
+}
+
+#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1)
+
+void iounmap(void *addr)
+{
+	if (!IS_KSEG1(addr))
+		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
+
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c
--- v2.4.6/linux/arch/mips/mm/loadmmu.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/mm/loadmmu.c	Wed Jul  4 11:50:39 2001
@@ -2,8 +2,8 @@
  * loadmmu.c: Setup cpu/cache specific function ptrs at boot time.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: loadmmu.c,v 1.17 2000/03/13 10:33:05 raiko Exp $
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -11,10 +11,11 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/bootinfo.h>
 
 /* memory functions */
 void (*_clear_page)(void * page);
@@ -22,84 +23,79 @@
 
 /* Cache operations. */
 void (*_flush_cache_all)(void);
+void (*___flush_cache_all)(void);
 void (*_flush_cache_mm)(struct mm_struct *mm);
 void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
 			  unsigned long end);
 void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 void (*_flush_cache_sigtramp)(unsigned long addr);
 void (*_flush_page_to_ram)(struct page * page);
+void (*_flush_icache_range)(unsigned long start, unsigned long end);
+void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page);
 
 /* DMA cache operations. */
 void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
 void (*_dma_cache_wback)(unsigned long start, unsigned long size);
 void (*_dma_cache_inv)(unsigned long start, unsigned long size);
 
-#ifdef CONFIG_CPU_R3000
-extern void ld_mmu_r2300(void);
-#endif
-#if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \
-    defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA)
+extern void ld_mmu_r23000(void);
 extern void ld_mmu_r4xx0(void);
-#endif
-#ifdef CONFIG_CPU_R6000
+extern void ld_mmu_r5432(void);
 extern void ld_mmu_r6000(void);
-#endif
-#ifdef CONFIG_CPU_R8000
+extern void ld_mmu_rm7k(void);
 extern void ld_mmu_tfp(void);
-#endif
-#ifdef CONFIG_CPU_R10000
 extern void ld_mmu_andes(void);
-#endif
+extern void ld_mmu_sb1(void);
+extern void ld_mmu_mips32(void);
 
 void __init loadmmu(void)
 {
-	switch(mips_cputype) {
-#ifdef CONFIG_CPU_R3000
-	case CPU_R2000:
-	case CPU_R3000:
-	case CPU_R3000A:
-	case CPU_R3081E:
-		printk("Loading R[23]00 MMU routines.\n");
-		ld_mmu_r2300();
-		break;
-#endif
 
+	if (mips_cpu.options & MIPS_CPU_4KTLB) {
 #if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \
     defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA)
-	case CPU_R4000PC:
-	case CPU_R4000SC:
-	case CPU_R4000MC:
-	case CPU_R4200:
-	case CPU_R4300:
-	case CPU_R4400PC:
-	case CPU_R4400SC:
-	case CPU_R4400MC:
-	case CPU_R4600:
-	case CPU_R4640:
-	case CPU_R4650:
-	case CPU_R4700:
-	case CPU_R5000:
-	case CPU_R5000A:
-	case CPU_NEVADA:
 		printk("Loading R4000 MMU routines.\n");
 		ld_mmu_r4xx0();
-		break;
+#endif
+#if defined(CONFIG_CPU_RM7000)
+               printk("Loading RM7000 MMU routines.\n");
+               ld_mmu_rm7k();
+#endif
+#if defined(CONFIG_CPU_R5432)
+		printk("Loading R5432 MMU routines.\n");
+		ld_mmu_r5432();
 #endif
 
+#if defined(CONFIG_CPU_MIPS32)
+		printk("Loading MIPS32 MMU routines.\n");
+		ld_mmu_mips32();
+#endif
+	} else switch(mips_cpu.cputype) {
+#ifdef CONFIG_CPU_R3000
+	case CPU_R2000:
+	case CPU_R3000:
+	case CPU_R3000A:
+	case CPU_TX3912:
+	case CPU_TX3922:
+	case CPU_TX3927:
+	case CPU_R3081E:
+		printk("Loading R[23]000 MMU routines.\n");
+		ld_mmu_r23000();
+		break;
+#endif
 #ifdef CONFIG_CPU_R10000
 	case CPU_R10000:
 		printk("Loading R10000 MMU routines.\n");
 		ld_mmu_andes();
 		break;
 #endif
-
+#ifdef CONFIG_CPU_SB1
+	case CPU_SB1:
+		printk("Loading SB1 MMU routines.\n");
+		ld_mmu_sb1();
+		break;
+#endif
 	default:
-		/* XXX We need an generic routine in the MIPS port
-		 * XXX to jabber stuff onto the screen on all machines
-		 * XXX before the console is setup.  The ARCS prom
-		 * XXX routines look good for this, but only the SGI
-		 * XXX code has a full library for that at this time.
-		 */
 		panic("Yeee, unsupported mmu/cache architecture.");
 	}
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/mips32.c linux/arch/mips/mm/mips32.c
--- v2.4.6/linux/arch/mips/mm/mips32.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mm/mips32.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,1078 @@
+/*
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * MIPS32 CPU variant specific MMU/Cache routines.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/bcache.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+				     "nop; nop; nop; nop; nop; nop;\n\t" \
+				     ".set reorder\n\t")
+
+/* Primary cache parameters. */
+static int icache_size, dcache_size; /* Size in bytes */
+static int ic_lsize, dc_lsize;       /* LineSize in bytes */
+
+/* Secondary cache (if present) parameters. */
+static unsigned int scache_size, sc_lsize;	/* Again, in bytes */
+
+#include <asm/cacheops.h>
+#include <asm/mips32_cache.h>
+
+#undef DEBUG_CACHE
+
+/*
+ * Dummy cache handling routines for machines without boardcaches
+ */
+static void no_sc_noop(void) {}
+
+static struct bcache_ops no_sc_ops = {
+	(void *)no_sc_noop, (void *)no_sc_noop,
+	(void *)no_sc_noop, (void *)no_sc_noop
+};
+
+struct bcache_ops *bcops = &no_sc_ops;
+
+
+/*
+ * Zero an entire page.
+ */
+
+static void mips32_clear_page_dc(unsigned long page)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=page; i<page+PAGE_SIZE; i+=dc_lsize)
+		{
+		        __asm__ __volatile__(
+			        ".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				".set\tmips3\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tmips0\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_D));
+		}
+	}
+	for (i=page; i<page+PAGE_SIZE; i+=4)
+	        *(unsigned long *)(i) = 0;
+}
+
+static void mips32_clear_page_sc(unsigned long page)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=page; i<page+PAGE_SIZE; i+=sc_lsize)
+		{
+		        __asm__ __volatile__(
+				".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				".set\tmips3\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tmips0\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_SD));
+		}
+	}
+	for (i=page; i<page+PAGE_SIZE; i+=4)
+	        *(unsigned long *)(i) = 0;
+}
+
+static void mips32_copy_page_dc(unsigned long to, unsigned long from)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=to; i<to+PAGE_SIZE; i+=dc_lsize)
+		{
+		        __asm__ __volatile__(
+			        ".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				".set\tmips3\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tmips0\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_D));
+		}
+	}
+	for (i=0; i<PAGE_SIZE; i+=4)
+	        *(unsigned long *)(to+i) = *(unsigned long *)(from+i);
+}
+
+static void mips32_copy_page_sc(unsigned long to, unsigned long from)
+{
+	unsigned long i;
+
+        if (mips_cpu.options & MIPS_CPU_CACHE_CDEX)
+	{
+	        for (i=to; i<to+PAGE_SIZE; i+=sc_lsize)
+		{
+		        __asm__ __volatile__(
+				".set\tnoreorder\n\t"
+				".set\tnoat\n\t"
+				".set\tmips3\n\t"
+				"cache\t%2,(%0)\n\t"
+				".set\tmips0\n\t"
+				".set\tat\n\t"
+				".set\treorder"
+				:"=r" (i)
+				:"0" (i),
+				"I" (Create_Dirty_Excl_SD));
+		}
+	}
+	for (i=0; i<PAGE_SIZE; i+=4)
+	        *(unsigned long *)(to+i) = *(unsigned long *)(from+i);
+}
+
+static inline void mips32_flush_cache_all_sc(void)
+{
+	unsigned long flags;
+
+	__save_and_cli(flags);
+	blast_dcache(); blast_icache(); blast_scache();
+	__restore_flags(flags);
+}
+
+static inline void mips32_flush_cache_all_pc(void)
+{
+	unsigned long flags;
+
+	__save_and_cli(flags);
+	blast_dcache(); blast_icache();
+	__restore_flags(flags);
+}
+
+static void
+mips32_flush_cache_range_sc(struct mm_struct *mm,
+			 unsigned long start,
+			 unsigned long end)
+{
+	struct vm_area_struct *vma;
+	unsigned long flags;
+
+	if(mm->context == 0)
+		return;
+
+	start &= PAGE_MASK;
+#ifdef DEBUG_CACHE
+	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
+#endif
+	vma = find_vma(mm, start);
+	if(vma) {
+		if(mm->context != current->mm->context) {
+			mips32_flush_cache_all_sc();
+		} else {
+			pgd_t *pgd;
+			pmd_t *pmd;
+			pte_t *pte;
+
+			__save_and_cli(flags);
+			while(start < end) {
+				pgd = pgd_offset(mm, start);
+				pmd = pmd_offset(pgd, start);
+				pte = pte_offset(pmd, start);
+
+				if(pte_val(*pte) & _PAGE_VALID)
+					blast_scache_page(start);
+				start += PAGE_SIZE;
+			}
+			__restore_flags(flags);
+		}
+	}
+}
+
+static void mips32_flush_cache_range_pc(struct mm_struct *mm,
+				     unsigned long start,
+				     unsigned long end)
+{
+	if(mm->context != 0) {
+		unsigned long flags;
+
+#ifdef DEBUG_CACHE
+		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
+#endif
+		__save_and_cli(flags);
+		blast_dcache(); blast_icache();
+		__restore_flags(flags);
+	}
+}
+
+/*
+ * On architectures like the Sparc, we could get rid of lines in
+ * the cache created only by a certain context, but on the MIPS
+ * (and actually certain Sparc's) we cannot.
+ */
+static void mips32_flush_cache_mm_sc(struct mm_struct *mm)
+{
+	if(mm->context != 0) {
+#ifdef DEBUG_CACHE
+		printk("cmm[%d]", (int)mm->context);
+#endif
+		mips32_flush_cache_all_sc();
+	}
+}
+
+static void mips32_flush_cache_mm_pc(struct mm_struct *mm)
+{
+	if(mm->context != 0) {
+#ifdef DEBUG_CACHE
+		printk("cmm[%d]", (int)mm->context);
+#endif
+		mips32_flush_cache_all_pc();
+	}
+}
+
+
+
+
+
+static void mips32_flush_cache_page_sc(struct vm_area_struct *vma,
+				    unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	/*
+	 * If ownes no valid ASID yet, cannot possibly have gotten
+	 * this page into the cache.
+	 */
+	if (mm->context == 0)
+		return;
+
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+	__save_and_cli(flags);
+	page &= PAGE_MASK;
+	pgdp = pgd_offset(mm, page);
+	pmdp = pmd_offset(pgdp, page);
+	ptep = pte_offset(pmdp, page);
+
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
+	 * in the cache.
+	 */
+	if (!(pte_val(*ptep) & _PAGE_VALID))
+		goto out;
+
+	/*
+	 * Doing flushes for another ASID than the current one is
+	 * too difficult since R4k caches do a TLB translation
+	 * for every cache flush operation.  So we do indexed flushes
+	 * in that case, which doesn't overly flush the cache too much.
+	 */
+	if (mm->context != current->active_mm->context) {
+		/*
+		 * Do indexed flush, too much work to get the (possible)
+		 * tlb refills to work correctly.
+		 */
+		page = (KSEG0 + (page & (scache_size - 1)));
+		blast_dcache_page_indexed(page);
+		blast_scache_page_indexed(page);
+	} else
+		blast_scache_page(page);
+out:
+	__restore_flags(flags);
+}
+
+static void mips32_flush_cache_page_pc(struct vm_area_struct *vma,
+				    unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	/*
+	 * If ownes no valid ASID yet, cannot possibly have gotten
+	 * this page into the cache.
+	 */
+	if (mm->context == 0)
+		return;
+
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+	__save_and_cli(flags);
+	page &= PAGE_MASK;
+	pgdp = pgd_offset(mm, page);
+	pmdp = pmd_offset(pgdp, page);
+	ptep = pte_offset(pmdp, page);
+
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
+	 * in the cache.
+	 */
+	if (!(pte_val(*ptep) & _PAGE_VALID))
+		goto out;
+
+	/*
+	 * Doing flushes for another ASID than the current one is
+	 * too difficult since Mips32 caches do a TLB translation
+	 * for every cache flush operation.  So we do indexed flushes
+	 * in that case, which doesn't overly flush the cache too much.
+	 */
+	if (mm == current->active_mm) {
+		blast_dcache_page(page);
+	} else {
+		/* Do indexed flush, too much work to get the (possible)
+		 * tlb refills to work correctly.
+		 */
+		page = (KSEG0 + (page & (dcache_size - 1)));
+		blast_dcache_page_indexed(page);
+	}
+out:
+	__restore_flags(flags);
+}
+
+/* If the addresses passed to these routines are valid, they are
+ * either:
+ *
+ * 1) In KSEG0, so we can do a direct flush of the page.
+ * 2) In KSEG2, and since every process can translate those
+ *    addresses all the time in kernel mode we can do a direct
+ *    flush.
+ * 3) In KSEG1, no flush necessary.
+ */
+static void mips32_flush_page_to_ram_sc(struct page *page)
+{
+	blast_scache_page((unsigned long)page_address(page));
+}
+
+static void mips32_flush_page_to_ram_pc(struct page *page)
+{
+	blast_dcache_page((unsigned long)page_address(page));
+}
+
+static void
+mips32_flush_icache_page_s(struct vm_area_struct *vma, struct page *page)
+{
+	/*
+	 * We did an scache flush therefore PI is already clean.
+	 */
+}
+
+static void
+mips32_flush_icache_range(unsigned long start, unsigned long end)
+{
+	flush_cache_all();
+}
+
+static void
+mips32_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+	int address;
+
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
+
+	address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK & (dcache_size - 1));
+	blast_icache_page_indexed(address);
+}
+
+/*
+ * Writeback and invalidate the primary cache dcache before DMA.
+ */
+static void
+mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+	unsigned int flags;
+
+	if (size >= dcache_size) {
+		flush_cache_all();
+	} else {
+	        __save_and_cli(flags);
+		a = addr & ~(dc_lsize - 1);
+		end = (addr + size) & ~(dc_lsize - 1);
+		while (1) {
+			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+			if (a == end) break;
+			a += dc_lsize;
+		}
+		__restore_flags(flags);
+	}
+	bc_wback_inv(addr, size);
+}
+
+static void
+mips32_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= scache_size) {
+		flush_cache_all();
+		return;
+	}
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		flush_scache_line(a);	/* Hit_Writeback_Inv_SD */
+		if (a == end) break;
+		a += sc_lsize;
+	}
+}
+
+static void
+mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+	unsigned int flags;
+
+	if (size >= dcache_size) {
+		flush_cache_all();
+	} else {
+	        __save_and_cli(flags);
+		a = addr & ~(dc_lsize - 1);
+		end = (addr + size) & ~(dc_lsize - 1);
+		while (1) {
+			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+			if (a == end) break;
+			a += dc_lsize;
+		}
+		__restore_flags(flags);
+	}
+
+	bc_inv(addr, size);
+}
+
+static void
+mips32_dma_cache_inv_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= scache_size) {
+		flush_cache_all();
+		return;
+	}
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		flush_scache_line(a); /* Hit_Writeback_Inv_SD */
+		if (a == end) break;
+		a += sc_lsize;
+	}
+}
+
+static void
+mips32_dma_cache_wback(unsigned long addr, unsigned long size)
+{
+	panic("mips32_dma_cache called - should not happen.\n");
+}
+
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case.  Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
+static void mips32_flush_cache_sigtramp(unsigned long addr)
+{
+	unsigned long daddr, iaddr;
+
+	daddr = addr & ~(dc_lsize - 1);
+	protected_writeback_dcache_line(daddr);
+	protected_writeback_dcache_line(daddr + dc_lsize);
+	iaddr = addr & ~(ic_lsize - 1);
+	protected_flush_icache_line(iaddr);
+	protected_flush_icache_line(iaddr + ic_lsize);
+}
+
+#undef DEBUG_TLB
+#undef DEBUG_TLBUPDATE
+
+void flush_tlb_all(void)
+{
+	unsigned long flags;
+	unsigned long old_ctx;
+	int entry;
+
+#ifdef DEBUG_TLB
+	printk("[tlball]");
+#endif
+
+	__save_and_cli(flags);
+	/* Save old context and create impossible VPN2 value */
+	old_ctx = (get_entryhi() & 0xff);
+	set_entryhi(KSEG0);
+	set_entrylo0(0);
+	set_entrylo1(0);
+	BARRIER;
+
+	entry = get_wired();
+
+	/* Blast 'em all away. */
+	while(entry < mips_cpu.tlbsize) {
+	        /* Make sure all entries differ. */  
+	        set_entryhi(KSEG0+entry*0x2000);
+		set_index(entry);
+		BARRIER;
+		tlb_write_indexed();
+		BARRIER;
+		entry++;
+	}
+	BARRIER;
+	set_entryhi(old_ctx);
+	__restore_flags(flags);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	if (mm->context != 0) {
+		unsigned long flags;
+
+#ifdef DEBUG_TLB
+		printk("[tlbmm<%d>]", mm->context);
+#endif
+		__save_and_cli(flags);
+		get_new_mmu_context(mm, asid_cache);
+		if (mm == current->active_mm)
+			set_entryhi(mm->context & 0xff);
+		__restore_flags(flags);
+	}
+}
+
+void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				unsigned long end)
+{
+	if(mm->context != 0) {
+		unsigned long flags;
+		int size;
+
+#ifdef DEBUG_TLB
+		printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
+		       start, end);
+#endif
+		__save_and_cli(flags);
+		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+		size = (size + 1) >> 1;
+		if(size <= mips_cpu.tlbsize/2) {
+			int oldpid = (get_entryhi() & 0xff);
+			int newpid = (mm->context & 0xff);
+
+			start &= (PAGE_MASK << 1);
+			end += ((PAGE_SIZE << 1) - 1);
+			end &= (PAGE_MASK << 1);
+			while(start < end) {
+				int idx;
+
+				set_entryhi(start | newpid);
+				start += (PAGE_SIZE << 1);
+				BARRIER;
+				tlb_probe();
+				BARRIER;
+				idx = get_index();
+				set_entrylo0(0);
+				set_entrylo1(0);
+				if(idx < 0)
+					continue;
+				/* Make sure all entries differ. */
+				set_entryhi(KSEG0+idx*0x2000);
+				BARRIER;
+				tlb_write_indexed();
+				BARRIER;
+			}
+			set_entryhi(oldpid);
+		} else {
+			get_new_mmu_context(mm, asid_cache);
+			if (mm == current->active_mm)
+				set_entryhi(mm->context & 0xff);
+		}
+		__restore_flags(flags);
+	}
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	if (vma->vm_mm->context != 0) {
+		unsigned long flags;
+		int oldpid, newpid, idx;
+
+#ifdef DEBUG_TLB
+		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+#endif
+		newpid = (vma->vm_mm->context & 0xff);
+		page &= (PAGE_MASK << 1);
+		__save_and_cli(flags);
+		oldpid = (get_entryhi() & 0xff);
+		set_entryhi(page | newpid);
+		BARRIER;
+		tlb_probe();
+		BARRIER;
+		idx = get_index();
+		set_entrylo0(0);
+		set_entrylo1(0);
+		if(idx < 0)
+			goto finish;
+		/* Make sure all entries differ. */  
+		set_entryhi(KSEG0+idx*0x2000);
+		BARRIER;
+		tlb_write_indexed();
+
+	finish:
+		BARRIER;
+		set_entryhi(oldpid);
+		__restore_flags(flags);
+	}
+}
+
+void pgd_init(unsigned long page)
+{
+	unsigned long *p = (unsigned long *) page;
+	int i;
+
+	for(i = 0; i < USER_PTRS_PER_PGD; i+=8) {
+		p[i + 0] = (unsigned long) invalid_pte_table;
+		p[i + 1] = (unsigned long) invalid_pte_table;
+		p[i + 2] = (unsigned long) invalid_pte_table;
+		p[i + 3] = (unsigned long) invalid_pte_table;
+		p[i + 4] = (unsigned long) invalid_pte_table;
+		p[i + 5] = (unsigned long) invalid_pte_table;
+		p[i + 6] = (unsigned long) invalid_pte_table;
+		p[i + 7] = (unsigned long) invalid_pte_table;
+	}
+}
+
+/* 
+ * Updates the TLB with the new pte(s).
+ */
+void update_mmu_cache(struct vm_area_struct * vma,
+		      unsigned long address, pte_t pte)
+{
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	int idx, pid;
+
+	/*
+	 * Handle debugger faulting in for debugee.
+	 */
+	if (current->active_mm != vma->vm_mm)
+		return;
+
+	pid = get_entryhi() & 0xff;
+
+#ifdef DEBUG_TLB
+	if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) {
+		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n",
+		       (int) (vma->vm_mm->context & 0xff), pid);
+	}
+#endif
+
+	__save_and_cli(flags);
+	address &= (PAGE_MASK << 1);
+	set_entryhi(address | (pid));
+	pgdp = pgd_offset(vma->vm_mm, address);
+	BARRIER;
+	tlb_probe();
+	BARRIER;
+	pmdp = pmd_offset(pgdp, address);
+	idx = get_index();
+	ptep = pte_offset(pmdp, address);
+	BARRIER;
+	set_entrylo0(pte_val(*ptep++) >> 6);
+	set_entrylo1(pte_val(*ptep) >> 6);
+	set_entryhi(address | (pid));
+	BARRIER;
+	if(idx < 0) {
+		tlb_write_random();
+	} else {
+		tlb_write_indexed();
+	}
+	BARRIER;
+	set_entryhi(pid);
+	BARRIER;
+	__restore_flags(flags);
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	/* Saved main processor registers. */
+	printk("$0 : %08lx %08lx %08lx %08lx\n",
+	       0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
+	printk("$4 : %08lx %08lx %08lx %08lx\n",
+               regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
+	printk("$8 : %08lx %08lx %08lx %08lx\n",
+	       regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
+	printk("$12: %08lx %08lx %08lx %08lx\n",
+               regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
+	printk("$16: %08lx %08lx %08lx %08lx\n",
+	       regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
+	printk("$20: %08lx %08lx %08lx %08lx\n",
+               regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
+	printk("$24: %08lx %08lx\n",
+	       regs->regs[24], regs->regs[25]);
+	printk("$28: %08lx %08lx %08lx %08lx\n",
+	       regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
+
+	/* Saved cp0 registers. */
+	printk("epc   : %08lx\nStatus: %08lx\nCause : %08lx\n",
+	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+			
+void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				      unsigned long entryhi, unsigned long pagemask)
+{
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        __save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        set_wired (wired + 1);
+        set_index (wired);
+        BARRIER;    
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;    
+        tlb_write_indexed();
+        BARRIER;    
+    
+        set_entryhi(old_ctx);
+        BARRIER;    
+        set_pagemask (old_pagemask);
+        flush_tlb_all();    
+        __restore_flags(flags);
+}
+
+/* Detect and size the various caches. */
+static void __init probe_icache(unsigned long config)
+{
+        unsigned long config1;
+	unsigned int lsize;
+
+        if (!(config & (1 << 31))) {
+	        /* 
+		 * Not a MIPS32 complainant CPU. 
+		 * Config 1 register not supported, we assume R4k style.
+		 */
+	        icache_size = 1 << (12 + ((config >> 9) & 7));
+		ic_lsize = 16 << ((config >> 5) & 1);
+		mips_cpu.icache.linesz = ic_lsize;
+		
+		/* 
+		 * We cannot infer associativity - assume direct map
+		 * unless probe template indicates otherwise
+		 */
+		if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1;
+		mips_cpu.icache.sets = 
+			(icache_size / ic_lsize) / mips_cpu.icache.ways;
+	} else {
+	       config1 = read_mips32_cp0_config1(); 
+
+	       if ((lsize = ((config1 >> 19) & 7)))
+		       mips_cpu.icache.linesz = 2 << lsize;
+	       else 
+		       mips_cpu.icache.linesz = lsize;
+	       mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7);
+	       mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7);
+
+	       ic_lsize = mips_cpu.icache.linesz;
+	       icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * 
+		             ic_lsize;
+	}
+	printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n",
+	       icache_size >> 10, ic_lsize, mips_cpu.icache.ways);
+}
+
+static void __init probe_dcache(unsigned long config)
+{
+        unsigned long config1;
+	unsigned int lsize;
+
+        if (!(config & (1 << 31))) {
+	        /* 
+		 * Not a MIPS32 complainant CPU. 
+		 * Config 1 register not supported, we assume R4k style.
+		 */  
+		dcache_size = 1 << (12 + ((config >> 6) & 7));
+		dc_lsize = 16 << ((config >> 4) & 1);
+		mips_cpu.dcache.linesz = dc_lsize;
+		/* 
+		 * We cannot infer associativity - assume direct map
+		 * unless probe template indicates otherwise
+		 */
+		if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1;
+		mips_cpu.dcache.sets = 
+			(dcache_size / dc_lsize) / mips_cpu.dcache.ways;
+	} else {
+	        config1 = read_mips32_cp0_config1();
+
+		if ((lsize = ((config1 >> 10) & 7)))
+		        mips_cpu.dcache.linesz = 2 << lsize;
+		else 
+		        mips_cpu.dcache.linesz= lsize;
+		mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7);
+		mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7);
+
+		dc_lsize = mips_cpu.dcache.linesz;
+		dcache_size = 
+			mips_cpu.dcache.sets * mips_cpu.dcache.ways
+			* dc_lsize;
+	}
+	printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n",
+	       dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways);
+}
+
+
+/* If you even _breathe_ on this function, look at the gcc output
+ * and make sure it does not pop things on and off the stack for
+ * the cache sizing loop that executes in KSEG1 space or else
+ * you will crash and burn badly.  You have been warned.
+ */
+static int __init probe_scache(unsigned long config)
+{
+	extern unsigned long stext;
+	unsigned long flags, addr, begin, end, pow2;
+	int tmp;
+
+	if (mips_cpu.scache.flags == MIPS_CACHE_NOT_PRESENT)
+		return 0;
+
+	tmp = ((config >> 17) & 1);
+	if(tmp)
+		return 0;
+	tmp = ((config >> 22) & 3);
+	switch(tmp) {
+	case 0:
+		sc_lsize = 16;
+		break;
+	case 1:
+		sc_lsize = 32;
+		break;
+	case 2:
+		sc_lsize = 64;
+		break;
+	case 3:
+		sc_lsize = 128;
+		break;
+	}
+
+	begin = (unsigned long) &stext;
+	begin &= ~((4 * 1024 * 1024) - 1);
+	end = begin + (4 * 1024 * 1024);
+
+	/* This is such a bitch, you'd think they would make it
+	 * easy to do this.  Away you daemons of stupidity!
+	 */
+	__save_and_cli(flags);
+
+	/* Fill each size-multiple cache line with a valid tag. */
+	pow2 = (64 * 1024);
+	for(addr = begin; addr < end; addr = (begin + pow2)) {
+		unsigned long *p = (unsigned long *) addr;
+		__asm__ __volatile__("nop" : : "r" (*p)); /* whee... */
+		pow2 <<= 1;
+	}
+
+	/* Load first line with zero (therefore invalid) tag. */
+	set_taglo(0);
+	set_taghi(0);
+	__asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */
+	__asm__ __volatile__("\n\t.set noreorder\n\t"
+			     ".set mips3\n\t"
+			     "cache 8, (%0)\n\t"
+			     ".set mips0\n\t"
+			     ".set reorder\n\t" : : "r" (begin));
+	__asm__ __volatile__("\n\t.set noreorder\n\t"
+			     ".set mips3\n\t"
+			     "cache 9, (%0)\n\t"
+			     ".set mips0\n\t"
+			     ".set reorder\n\t" : : "r" (begin));
+	__asm__ __volatile__("\n\t.set noreorder\n\t"
+			     ".set mips3\n\t"
+			     "cache 11, (%0)\n\t"
+			     ".set mips0\n\t"
+			     ".set reorder\n\t" : : "r" (begin));
+
+	/* Now search for the wrap around point. */
+	pow2 = (128 * 1024);
+	tmp = 0;
+	for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) {
+		__asm__ __volatile__("\n\t.set noreorder\n\t"
+				     ".set mips3\n\t"
+				     "cache 7, (%0)\n\t"
+				     ".set mips0\n\t"
+				     ".set reorder\n\t" : : "r" (addr));
+		__asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */
+		if(!get_taglo())
+			break;
+		pow2 <<= 1;
+	}
+	__restore_flags(flags);
+	addr -= begin;
+	printk("Secondary cache sized at %dK linesize %d bytes.\n",
+	       (int) (addr >> 10), sc_lsize);
+	scache_size = addr;
+	return 1;
+}
+
+static void __init setup_noscache_funcs(void)
+{
+	_clear_page = (void *)mips32_clear_page_dc;
+	_copy_page = (void *)mips32_copy_page_dc;
+	_flush_cache_all = mips32_flush_cache_all_pc;
+	___flush_cache_all = mips32_flush_cache_all_pc;
+	_flush_cache_mm = mips32_flush_cache_mm_pc;
+	_flush_cache_range = mips32_flush_cache_range_pc;
+	_flush_cache_page = mips32_flush_cache_page_pc;
+	_flush_page_to_ram = mips32_flush_page_to_ram_pc;
+
+	_flush_icache_page = mips32_flush_icache_page;
+
+	_dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc;
+	_dma_cache_wback = mips32_dma_cache_wback;
+	_dma_cache_inv = mips32_dma_cache_inv_pc;
+}
+
+static void __init setup_scache_funcs(void)
+{
+        _flush_cache_all = mips32_flush_cache_all_sc;
+        ___flush_cache_all = mips32_flush_cache_all_sc;
+	_flush_cache_mm = mips32_flush_cache_mm_sc;
+	_flush_cache_range = mips32_flush_cache_range_sc;
+	_flush_cache_page = mips32_flush_cache_page_sc;
+	_flush_page_to_ram = mips32_flush_page_to_ram_sc;
+	_clear_page = (void *)mips32_clear_page_sc;
+	_copy_page = (void *)mips32_copy_page_sc;
+
+	_flush_icache_page = mips32_flush_icache_page_s;
+
+	_dma_cache_wback_inv = mips32_dma_cache_wback_inv_sc;
+	_dma_cache_wback = mips32_dma_cache_wback;
+	_dma_cache_inv = mips32_dma_cache_inv_sc;
+}
+
+typedef int (*probe_func_t)(unsigned long);
+
+static inline void __init setup_scache(unsigned int config)
+{
+	probe_func_t probe_scache_kseg1;
+	int sc_present = 0;
+
+	/* Maybe the cpu knows about a l2 cache? */
+	probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
+	sc_present = probe_scache_kseg1(config);
+
+	if (sc_present) {
+	  	mips_cpu.scache.linesz = sc_lsize;
+		/* 
+		 * We cannot infer associativity - assume direct map
+		 * unless probe template indicates otherwise
+		 */
+		if(!mips_cpu.scache.ways) mips_cpu.scache.ways = 1;
+		mips_cpu.scache.sets = 
+		  (scache_size / sc_lsize) / mips_cpu.scache.ways;
+
+		setup_scache_funcs();
+		return;
+	}
+
+	setup_noscache_funcs();
+}
+
+static void __init probe_tlb(unsigned long config)
+{
+        unsigned long config1;
+
+        if (!(config & (1 << 31))) {
+	        /* 
+		 * Not a MIPS32 complainant CPU. 
+		 * Config 1 register not supported, we assume R4k style.
+		 */  
+	        mips_cpu.tlbsize = 48;
+	} else {
+	        config1 = read_mips32_cp0_config1();
+		if (!((config >> 7) & 3))
+		        panic("No MMU present");
+		else
+		        mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1;
+	}	
+
+	printk("Number of TLB entries %d.\n", mips_cpu.tlbsize);
+}
+
+void __init ld_mmu_mips32(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+
+	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
+
+#ifdef CONFIG_MIPS_UNCACHED
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+#else
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+#endif
+
+	probe_icache(config);
+	probe_dcache(config);
+	setup_scache(config);
+	probe_tlb(config);
+
+	_flush_cache_sigtramp = mips32_flush_cache_sigtramp;
+	_flush_icache_range = mips32_flush_icache_range;	/* Ouch */
+
+	__flush_cache_all();
+	write_32bit_cp0_register(CP0_WIRED, 0);
+
+	/*
+	 * You should never change this register:
+	 *   - The entire mm handling assumes the c0_pagemask register to
+	 *     be set for 4kb pages.
+	 */
+	write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
+	flush_tlb_all();
+}
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c
--- v2.4.6/linux/arch/mips/mm/r2300.c	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/mm/r2300.c	Wed Jul  4 11:50:39 2001
@@ -4,7 +4,8 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
  * with a lot of changes to make this thing work for R3000s
- * Copyright (C) 1998, 2000 Harald Koerfgen
+ * Tx39XX R4k style caches added. HK
+ * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
  */
 #include <linux/init.h>
@@ -19,6 +20,8 @@
 #include <asm/isadep.h>
 #include <asm/io.h>
 #include <asm/wbflush.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
 
 /*
  * According to the paper written by D. Miller about Linux cache & TLB
@@ -27,15 +30,17 @@
  * Define this if driver does not handle cache consistency during DMA ops.
  */
 
-/* Primary cache parameters. */
-static int icache_size, dcache_size; /* Size in bytes */
-/* the linesizes are usually fixed on R3000s */
+/* For R3000 cores with R4000 style caches */
+static unsigned long icache_size, dcache_size;		/* Size in bytes */
+static unsigned long icache_lsize, dcache_lsize;	/* Size in bytes */
+static unsigned long scache_size = 0;
+
+#include <asm/cacheops.h>
+#include <asm/r4kcache.h>
 
 #undef DEBUG_TLB
 #undef DEBUG_CACHE
 
-#define NTLB_ENTRIES       64  /* Fixed on all R23000 variants... */
-
 /* page functions */
 void r3k_clear_page(void * page)
 {
@@ -120,7 +125,7 @@
 
 	p = (volatile unsigned long *) KSEG0;
 
-	save_and_cli(flags);
+	flags = read_32bit_cp0_register(CP0_STATUS);
 
 	/* isolate cache space */
 	write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC);
@@ -142,34 +147,30 @@
 		if (size > 0x40000)
 			size = 0;
 	}
-	restore_flags(flags);
+	write_32bit_cp0_register(CP0_STATUS, flags);
 
 	return size * sizeof(*p);
 }
 
-static void __init probe_dcache(void)
+static void __init r3k_probe_cache(void)
 {
 	dcache_size = r3k_cache_size(ST0_ISC);
-	printk("Primary data cache %dkb, linesize 4 bytes\n",
-		dcache_size >> 10);
-}
+	dcache_lsize = 4;
 
-static void __init probe_icache(void)
-{
 	icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
-	printk("Primary instruction cache %dkb, linesize 4 bytes\n",
-		icache_size >> 10);
+	icache_lsize = 4;
 }
 
-static void r3k_flush_icache_range(unsigned long start, unsigned long size)
+static void r3k_flush_icache_range(unsigned long start, unsigned long end)
 {
-	unsigned long i, flags;
+	unsigned long size, i, flags;
 	volatile unsigned char *p = (char *)start;
 
+	size = end - start;
 	if (size > icache_size)
 		size = icache_size;
 
-	save_and_cli(flags);
+	flags = read_32bit_cp0_register(CP0_STATUS);
 
 	/* isolate cache space */
 	write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
@@ -211,18 +212,19 @@
 		p += 0x080;
 	}
 
-	restore_flags(flags);
+	write_32bit_cp0_register(CP0_STATUS,flags);
 }
 
-static void r3k_flush_dcache_range(unsigned long start, unsigned long size)
+static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
 {
-	unsigned long i, flags;
+	unsigned long size, i, flags;
 	volatile unsigned char *p = (char *)start;
 
+	size = end - start;
 	if (size > dcache_size)
 		size = dcache_size;
 
-	save_and_cli(flags);
+	flags = read_32bit_cp0_register(CP0_STATUS);
 
 	/* isolate cache space */
 	write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|flags)&~ST0_IEC);
@@ -264,7 +266,7 @@
 		p += 0x080;
 	}
 
-	restore_flags(flags);
+	write_32bit_cp0_register(CP0_STATUS,flags);
 }
 
 static inline unsigned long get_phys_page (unsigned long addr,
@@ -279,15 +281,15 @@
 	pmd = pmd_offset(pgd, addr);
 	pte = pte_offset(pmd, addr);
 
-	if((physpage = pte_val(*pte)) & _PAGE_VALID)
-		return KSEG1ADDR(physpage & PAGE_MASK);
-	else
-		return 0;
+	if ((physpage = pte_val(*pte)) & _PAGE_VALID)
+		return KSEG0ADDR(physpage & PAGE_MASK);
+
+	return 0;
 }
 
 static inline void r3k_flush_cache_all(void)
 {
-	r3k_flush_icache_range(KSEG0, icache_size);
+	r3k_flush_icache_range(KSEG0, KSEG0 + icache_size);
 }
  
 static void r3k_flush_cache_mm(struct mm_struct *mm)
@@ -301,9 +303,8 @@
 	}
 }
 
-static void r3k_flush_cache_range(struct mm_struct *mm,
-				    unsigned long start,
-				    unsigned long end)
+static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start,
+				  unsigned long end)
 {
 	struct vm_area_struct *vma;
 
@@ -315,21 +316,22 @@
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
 	vma = find_vma(mm, start);
-	if (vma) {
-		if (mm->context != current->active_mm->context) {
-			flush_cache_all();
-		} else {
-			unsigned long flags, physpage;
+	if (!vma)
+		return;
 
-			save_and_cli(flags);
-			while (start < end) {
-				if ((physpage = get_phys_page(start, mm)))
-					r3k_flush_icache_range(physpage, PAGE_SIZE);
-		
-				start += PAGE_SIZE;
-			}
-			restore_flags(flags);
+	if (mm->context != current->active_mm->context) {
+		flush_cache_all();
+	} else {
+		unsigned long flags, physpage;
+
+		save_and_cli(flags);
+		while (start < end) {
+			if ((physpage = get_phys_page(start, mm)))
+				r3k_flush_icache_range(physpage,
+				                       physpage + PAGE_SIZE);
+			start += PAGE_SIZE;
 		}
+		restore_flags(flags);
 	}
 }
 
@@ -348,8 +350,7 @@
 		unsigned long physpage;
 
 		if ((physpage = get_phys_page(page, vma->vm_mm)))
-			r3k_flush_icache_range(physpage, PAGE_SIZE);
-
+			r3k_flush_icache_range(physpage, physpage + PAGE_SIZE);
 	}
 }
 
@@ -360,6 +361,26 @@
 	 */
 }
 
+static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long physpage;
+
+	if (mm->context == 0)
+		return;
+
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
+
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+
+	physpage = (unsigned long) page_address(page);
+	if (physpage)
+		r3k_flush_icache_range(physpage, physpage + PAGE_SIZE);
+}
+
 static void r3k_flush_cache_sigtramp(unsigned long addr)
 {
 	unsigned long flags;
@@ -367,26 +388,23 @@
 #ifdef DEBUG_CACHE
 	printk("csigtramp[%08lx]", addr);
 #endif
-	/*
-	 * I am assuming an 8 Byte cacheline here. HK
-	 */
-	addr &= ~7;
 
-	save_and_cli(flags);
+	flags = read_32bit_cp0_register(CP0_STATUS);
 
 	write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
 
 	asm ( 	"sb\t$0,0x000(%0)\n\t"
+		"sb\t$0,0x004(%0)\n\t"
 		"sb\t$0,0x008(%0)\n\t"
 		: : "r" (addr) );
 
-	restore_flags(flags);
+	write_32bit_cp0_register(CP0_STATUS, flags);
 }
 
 static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
 {
 	wbflush();
-	r3k_flush_dcache_range(start, size);
+	r3k_flush_dcache_range(start, start + size);
 }
 
 /* TLB operations. */
@@ -403,7 +421,7 @@
 	save_and_cli(flags);
 	old_ctx = (get_entryhi() & 0xfc0);
 	write_32bit_cp0_register(CP0_ENTRYLO0, 0);
-	for(entry = 0; entry < NTLB_ENTRIES; entry++) {
+	for (entry = 8; entry < mips_cpu.tlbsize; entry++) {
 		write_32bit_cp0_register(CP0_INDEX, entry << 8);
 		write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12));
 		__asm__ __volatile__("tlbwi");
@@ -418,7 +436,7 @@
 		unsigned long flags;
 
 #ifdef DEBUG_TLB
-		printk("[tlbmm<%d>]", mm->context);
+		printk("[tlbmm<%lu>]", (unsigned long) mm->context);
 #endif
 		save_and_cli(flags);
 		get_new_mmu_context(mm, asid_cache);
@@ -429,19 +447,19 @@
 }
 
 void flush_tlb_range(struct mm_struct *mm, unsigned long start,
-				  unsigned long end)
+                     unsigned long end)
 {
 	if (mm->context != 0) {
 		unsigned long flags;
 		int size;
 
 #ifdef DEBUG_TLB
-		printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xfc0),
-		       start, end);
+		printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
+			(mm->context & 0xfc0), start, end);
 #endif
 		save_and_cli(flags);
 		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-		if(size <= NTLB_ENTRIES) {
+		if(size <= mips_cpu.tlbsize) {
 			int oldpid = (get_entryhi() & 0xfc0);
 			int newpid = (mm->context & 0xfc0);
 
@@ -478,7 +496,7 @@
 		int oldpid, newpid, idx;
 
 #ifdef DEBUG_TLB
-		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+		printk("[tlbpage<%lu,0x%08lx>]", vma->vm_mm->context, page);
 #endif
 		newpid = (vma->vm_mm->context & 0xfc0);
 		page &= PAGE_MASK;
@@ -531,8 +549,8 @@
 		 "1" (PAGE_SIZE/(sizeof(pmd_t)*8)));
 }
 
-void update_mmu_cache(struct vm_area_struct * vma,
-				   unsigned long address, pte_t pte)
+void update_mmu_cache(struct vm_area_struct * vma, unsigned long address,
+                      pte_t pte)
 {
 	unsigned long flags;
 	pgd_t *pgdp;
@@ -550,8 +568,8 @@
 
 #ifdef DEBUG_TLB
 	if((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) {
-		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n",
-		       (int) (vma->vm_mm->context & 0xfc0), pid);
+		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n",
+		       (vma->vm_mm->context & 0xfc0), pid);
 	}
 #endif
 
@@ -576,19 +594,6 @@
 		printk("[HIT]");
 #endif
 	}
-#if 0
-	if(!strcmp(current->comm, "args")) {
-		printk("<");
-		for(idx = 0; idx < NTLB_ENTRIES; idx++) {
-			set_index(idx);
-			tlb_read();
-			address = get_entryhi();
-			if((address & 0xfc0) != 0)
-				printk("[%08lx]", address);
-		}
-		printk(">\n");
-	}
-#endif
 	set_entryhi(pid);
 	restore_flags(flags);
 }
@@ -626,33 +631,135 @@
 	       (unsigned int) regs->cp0_cause);
 }
 
+/* Todo: handle r4k-style TX39 TLB */
 void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
-				  unsigned long entryhi, unsigned long pagemask)
+                     unsigned long entryhi, unsigned long pagemask)
 {
-printk("r3k_add_wired_entry");
-        /*
-	 * FIXME, to be done
-	 */
+	unsigned long flags;
+	unsigned long old_ctx;
+	static unsigned long wired = 0;
+	
+	if (wired < 8) {
+		save_and_cli(flags);
+		old_ctx = get_entryhi() & 0xfc0;
+		set_entrylo0(entrylo0);
+		set_entryhi(entryhi);
+		set_index(wired);
+		wired++;
+		tlb_write_indexed();
+		set_entryhi(old_ctx);
+	        flush_tlb_all();    
+		restore_flags(flags);
+	}
 }
 
-void __init ld_mmu_r2300(void)
+static void tx39_flush_icache_all(void )
 {
+
+	unsigned long start = KSEG0;
+	unsigned long end = (start + icache_size);
+	unsigned long dummy = 0;
+
+	/* disable icache and stop streaming */
+	__asm__ __volatile__(
+	".set\tnoreorder\n\t"
+	"mfc0\t%0,$3\n\t"
+	"xori\t%0,32\n\t"
+	"mtc0\t%0,$3\n\t"
+	"j\t1f\n\t"
+	"nop\n\t"
+	"1:\t.set\treorder\n\t"
+	: : "r"(dummy));
+
+	/* invalidate icache */
+	while (start < end) {
+		cache16_unroll32(start,Index_Invalidate_I);
+		start += 0x200;
+	}
+
+	/* enable icache */
+	__asm__ __volatile__(
+	".set\tnoreorder\n\t"
+	"mfc0\t%0,$3\n\t"
+	"xori\t%0,32\n\t"
+	"mtc0\t%0,$3\n\t"
+	".set\treorder\n\t"
+	: : "r"(dummy));
+}
+
+static __init void tx39_probe_cache(void)
+{
+	unsigned long	config;
+
+	config = read_32bit_cp0_register(CP0_CONF);
+
+	icache_size = 1 << (10 + ((config >> 19) & 3));
+	icache_lsize = 16;
+
+	dcache_size = 1 << (10 + ((config >> 16) & 3));
+	dcache_lsize = 4;
+}
+
+void __init ld_mmu_r23000(void)
+{
+	unsigned long config;
+
 	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
 
 	_clear_page = r3k_clear_page;
 	_copy_page = r3k_copy_page;
 
-	probe_icache();
-	probe_dcache();
-
-	_flush_cache_all = r3k_flush_cache_all;
-	_flush_cache_mm = r3k_flush_cache_mm;
-	_flush_cache_range = r3k_flush_cache_range;
-	_flush_cache_page = r3k_flush_cache_page;
-	_flush_cache_sigtramp = r3k_flush_cache_sigtramp;
-	_flush_page_to_ram = r3k_flush_page_to_ram;
-
-        _dma_cache_wback_inv = r3k_dma_cache_wback_inv;
+	switch (mips_cpu.cputype) {
+	case CPU_R2000:
+	case CPU_R3000:
+	case CPU_R3000A:
+	case CPU_R3081:
+	case CPU_R3081E:
+
+		r3k_probe_cache();
+
+		_flush_cache_all = r3k_flush_cache_all;
+		___flush_cache_all = r3k_flush_cache_all;
+		_flush_cache_mm = r3k_flush_cache_mm;
+		_flush_cache_range = r3k_flush_cache_range;
+		_flush_cache_page = r3k_flush_cache_page;
+		_flush_cache_sigtramp = r3k_flush_cache_sigtramp;
+		_flush_page_to_ram = r3k_flush_page_to_ram;
+		_flush_icache_page = r3k_flush_icache_page;
+		_flush_icache_range = r3k_flush_icache_range;
+
+		_dma_cache_wback_inv = r3k_dma_cache_wback_inv;
+		break;
+
+	case CPU_TX3912:
+	case CPU_TX3922:
+	case CPU_TX3927:
+
+		config=read_32bit_cp0_register(CP0_CONF);
+		config &= ~TX39_CONF_WBON;
+		write_32bit_cp0_register(CP0_CONF, config);
+
+		tx39_probe_cache();
+
+		_flush_cache_all = tx39_flush_icache_all;
+		___flush_cache_all = tx39_flush_icache_all;
+		_flush_cache_mm = tx39_flush_icache_all;
+		_flush_cache_range = tx39_flush_icache_all;
+		_flush_cache_page = tx39_flush_icache_all;
+		_flush_cache_sigtramp = tx39_flush_icache_all;
+		_flush_page_to_ram = r3k_flush_page_to_ram;
+		_flush_icache_page = tx39_flush_icache_all;
+		_flush_icache_range = tx39_flush_icache_all;
+
+		_dma_cache_wback_inv = r3k_dma_cache_wback_inv;
+
+		break;
+	}
+
+	printk("Primary instruction cache %dkb, linesize %d bytes\n",
+		(int) (icache_size >> 10), (int) icache_lsize);
+	printk("Primary data cache %dkb, linesize %d bytes\n",
+		(int) (dcache_size >> 10), (int) dcache_lsize);
 
 	flush_tlb_all();
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.4.6/linux/arch/mips/mm/r4xx0.c	Sun Aug  6 11:43:17 2000
+++ linux/arch/mips/mm/r4xx0.c	Wed Jul  4 11:50:39 2001
@@ -19,12 +19,13 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
 #include <asm/bcache.h>
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/bootinfo.h>
 #include <asm/mmu_context.h>
 
 /* CP0 hazard avoidance. */
@@ -208,7 +209,7 @@
 {
 	unsigned int flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	*(volatile unsigned int *)KSEG1;
 	__asm__ __volatile__(
 		".set\tnoreorder\n\t"
@@ -235,7 +236,7 @@
 		 "I" (PAGE_SIZE),
 		 "i" (Create_Dirty_Excl_D)
 		:"$1","memory");
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 /*
@@ -626,7 +627,7 @@
 		:"0" (to), "1" (from),
 		 "I" (PAGE_SIZE),
 		 "i" (Create_Dirty_Excl_D));
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 /*
@@ -910,81 +911,81 @@
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache16(); blast_icache16(); blast_scache16();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_s32d16i16(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache16(); blast_icache16(); blast_scache32();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_s64d16i16(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache16(); blast_icache16(); blast_scache64();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_s128d16i16(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache16(); blast_icache16(); blast_scache128();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_s32d32i32(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache32(); blast_icache32(); blast_scache32();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_s64d32i32(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache32(); blast_icache32(); blast_scache64();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_s128d32i32(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache32(); blast_icache32(); blast_scache128();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_d16i16(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache16(); blast_icache16();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static inline void r4k_flush_cache_all_d32i32(void)
 {
 	unsigned long flags;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	blast_dcache32(); blast_icache32();
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void
@@ -1010,10 +1011,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1023,7 +1022,7 @@
 					blast_scache16_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1051,10 +1050,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1064,7 +1061,7 @@
 					blast_scache32_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1091,10 +1088,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1104,7 +1099,7 @@
 					blast_scache64_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1131,10 +1126,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1144,7 +1137,7 @@
 					blast_scache128_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1171,10 +1164,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1184,7 +1175,7 @@
 					blast_scache32_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1211,10 +1202,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1224,7 +1213,7 @@
 					blast_scache64_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1251,10 +1240,8 @@
 			pgd_t *pgd;
 			pmd_t *pmd;
 			pte_t *pte;
-			int text;
 
-			save_and_cli(flags);
-			text = vma->vm_flags & VM_EXEC;
+			__save_and_cli(flags);
 			while(start < end) {
 				pgd = pgd_offset(mm, start);
 				pmd = pmd_offset(pgd, start);
@@ -1264,7 +1251,7 @@
 					blast_scache128_page(start);
 				start += PAGE_SIZE;
 			}
-			restore_flags(flags);
+			__restore_flags(flags);
 		}
 	}
 }
@@ -1279,9 +1266,9 @@
 #ifdef DEBUG_CACHE
 		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		blast_dcache16(); blast_icache16();
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
 }
 
@@ -1295,9 +1282,9 @@
 #ifdef DEBUG_CACHE
 		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		blast_dcache32(); blast_icache32();
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
 }
 
@@ -1404,7 +1391,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1416,7 +1402,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1429,25 +1415,24 @@
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
-	/* Doing flushes for another ASID than the current one is
+	/*
+	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
 	if (mm->context != current->active_mm->context) {
-		/* Do indexed flush, too much work to get the (possible)
+		/*
+		 * Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache16_page_indexed(page);
-		if(text)
-			blast_icache16_page_indexed(page);
 		blast_scache16_page_indexed(page);
 	} else
 		blast_scache16_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma,
@@ -1458,7 +1443,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1470,7 +1454,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1482,25 +1466,24 @@
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
-	/* Doing flushes for another ASID than the current one is
+	/*
+	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
 	if (mm->context != current->active_mm->context) {
-		/* Do indexed flush, too much work to get the (possible)
+		/*
+		 * Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache16_page_indexed(page);
-		if(text)
-			blast_icache16_page_indexed(page);
 		blast_scache32_page_indexed(page);
 	} else
 		blast_scache32_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma,
@@ -1511,7 +1494,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1523,7 +1505,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1535,7 +1517,6 @@
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1543,18 +1524,17 @@
 	 * in that case, which doesn't overly flush the cache too much.
 	 */
 	if (mm->context != current->active_mm->context) {
-		/* Do indexed flush, too much work to get the (possible)
+		/*
+		 * Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache16_page_indexed(page);
-		if(text)
-			blast_icache16_page_indexed(page);
 		blast_scache64_page_indexed(page);
 	} else
 		blast_scache64_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma,
@@ -1565,7 +1545,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1577,7 +1556,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1590,8 +1569,8 @@
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
-	/* Doing flushes for another ASID than the current one is
+	/*
+	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
 	 * for every cache flush operation.  So we do indexed flushes
 	 * in that case, which doesn't overly flush the cache too much.
@@ -1603,13 +1582,11 @@
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache16_page_indexed(page);
-		if(text)
-			blast_icache16_page_indexed(page);
 		blast_scache128_page_indexed(page);
 	} else
 		blast_scache128_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma,
@@ -1620,7 +1597,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1632,7 +1608,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1645,7 +1621,6 @@
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1659,13 +1634,11 @@
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache32_page_indexed(page);
-		if(text)
-			blast_icache32_page_indexed(page);
 		blast_scache32_page_indexed(page);
 	} else
 		blast_scache32_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma,
@@ -1676,7 +1649,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1688,7 +1660,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1701,7 +1673,6 @@
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1715,13 +1686,11 @@
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache32_page_indexed(page);
-		if(text)
-			blast_icache32_page_indexed(page);
 		blast_scache64_page_indexed(page);
 	} else
 		blast_scache64_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma,
@@ -1732,7 +1701,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1744,19 +1712,19 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
 	ptep = pte_offset(pmdp, page);
 
-	/* If the page isn't marked valid, the page cannot possibly be
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
 	 * in the cache.
 	 */
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1769,13 +1737,11 @@
 		 */
 		page = (KSEG0 + (page & (scache_size - 1)));
 		blast_dcache32_page_indexed(page);
-		if(text)
-			blast_icache32_page_indexed(page);
 		blast_scache128_page_indexed(page);
 	} else
 		blast_scache128_page(page);
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma,
@@ -1786,7 +1752,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1798,19 +1763,19 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
 	ptep = pte_offset(pmdp, page);
 
-	/* If the page isn't marked valid, the page cannot possibly be
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
 	 * in the cache.
 	 */
 	if (!(pte_val(*ptep) & _PAGE_VALID))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1819,19 +1784,15 @@
 	 */
 	if (mm == current->active_mm) {
 		blast_dcache16_page(page);
-		if(text)
-			blast_icache16_page(page);
 	} else {
 		/* Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
 		 */
 		page = (KSEG0 + (page & (dcache_size - 1)));
 		blast_dcache16_page_indexed(page);
-		if(text)
-			blast_icache16_page_indexed(page);
 	}
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma,
@@ -1842,7 +1803,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1854,7 +1814,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1867,7 +1827,6 @@
 	if (!(pte_val(*ptep) & _PAGE_PRESENT))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1876,8 +1835,6 @@
 	 */
 	if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
 		blast_dcache32_page(page);
-		if(text)
-			blast_icache32_page(page);
 	} else {
 		/*
 		 * Do indexed flush, too much work to get the (possible)
@@ -1885,11 +1842,9 @@
 		 */
 		page = (KSEG0 + (page & (dcache_size - 1)));
 		blast_dcache32_page_indexed(page);
-		if(text)
-			blast_icache32_page_indexed(page);
 	}
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma,
@@ -1900,7 +1855,6 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int text;
 
 	/*
 	 * If ownes no valid ASID yet, cannot possibly have gotten
@@ -1912,7 +1866,7 @@
 #ifdef DEBUG_CACHE
 	printk("cpage[%d,%08lx]", (int)mm->context, page);
 #endif
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	page &= PAGE_MASK;
 	pgdp = pgd_offset(mm, page);
 	pmdp = pmd_offset(pgdp, page);
@@ -1925,7 +1879,6 @@
 	if (!(pte_val(*ptep) & _PAGE_PRESENT))
 		goto out;
 
-	text = (vma->vm_flags & VM_EXEC);
 	/*
 	 * Doing flushes for another ASID than the current one is
 	 * too difficult since stupid R4k caches do a TLB translation
@@ -1934,8 +1887,6 @@
 	 */
 	if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
 		blast_dcache32_page(page);
-		if(text)
-			blast_icache32_page(page);
 	} else {
 		/* Do indexed flush, too much work to get the (possible)
 		 * tlb refills to work correctly.
@@ -1943,13 +1894,9 @@
 		page = (KSEG0 + (page & (dcache_size - 1)));
 		blast_dcache32_page_indexed(page);
 		blast_dcache32_page_indexed(page ^ dcache_waybit);
-		if(text) {
-			blast_icache32_page_indexed(page);
-			blast_icache32_page_indexed(page ^ icache_waybit);
-		}
 	}
 out:
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 /* If the addresses passed to these routines are valid, they are
@@ -1961,120 +1908,71 @@
  *    flush.
  * 3) In KSEG1, no flush necessary.
  */
-static void r4k_flush_page_to_ram_s16d16i16(struct page * page)
+static void r4k_flush_page_to_ram_s16(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache16_page(addr);
-	}
+	blast_scache16_page((unsigned long)page_address(page));
 }
 
-static void r4k_flush_page_to_ram_s32d16i16(struct page * page)
+static void r4k_flush_page_to_ram_s32(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache32_page(addr);
-	}
+	blast_scache32_page((unsigned long)page_address(page));
 }
 
-static void r4k_flush_page_to_ram_s64d16i16(struct page * page)
+static void r4k_flush_page_to_ram_s64(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache64_page(addr);
-	}
+	blast_scache64_page((unsigned long)page_address(page));
 }
 
-static void r4k_flush_page_to_ram_s128d16i16(struct page * page)
+static void r4k_flush_page_to_ram_s128(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache128_page(addr);
-	}
+	blast_scache128_page((unsigned long)page_address(page));
 }
 
-static void r4k_flush_page_to_ram_s32d32i32(struct page * page)
+static void r4k_flush_page_to_ram_d16(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache32_page(addr);
-	}
+	blast_dcache16_page((unsigned long)page_address(page));
 }
 
-static void r4k_flush_page_to_ram_s64d32i32(struct page * page)
+static void r4k_flush_page_to_ram_d32(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache64_page(addr);
-	}
+	blast_dcache32_page((unsigned long)page_address(page));
 }
 
-static void r4k_flush_page_to_ram_s128d32i32(struct page * page)
+static void r4k_flush_page_to_ram_d32_r4600(struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
+	unsigned long flags;
 
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		blast_scache128_page(addr);
-	}
+	__save_and_cli(flags);			/* For R4600 v1.7 bug.  */
+	blast_dcache32_page((unsigned long)page_address(page));
+	__restore_flags(flags);
 }
 
-static void r4k_flush_page_to_ram_d16i16(struct page * page)
+static void
+r4k_flush_icache_page_s(struct vm_area_struct *vma, struct page *page)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
-
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-		unsigned long flags;
-
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		__save_and_cli(flags);
-		blast_dcache16_page(addr);
-		__restore_flags(flags);
-	}
+	/*
+	 * We did an scache flush therefore PI is already clean.
+	 */
 }
 
-static void r4k_flush_page_to_ram_d32i32(struct page * page)
+static void
+r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
-	unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK;
+	flush_cache_all();
+}
 
-	if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) {
-		unsigned long flags;
+/*
+ * Ok, this seriously sucks.  We use them to flush a user page but don't
+ * know the virtual address, so we have to blast away the whole icache
+ * which is significantly more expensive than the real thing.
+ */
+static void
+r4k_flush_icache_page_p(struct vm_area_struct *vma, struct page *page)
+{
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
 
-#ifdef DEBUG_CACHE
-		printk("cram[%08lx]", addr);
-#endif
-		__save_and_cli(flags);
-		blast_dcache32_page(addr);
-		__restore_flags(flags);
-	}
+	flush_cache_all();
 }
 
 /*
@@ -2098,7 +1996,7 @@
 		flush_cache_all();
 	} else {
 		/* Workaround for R4600 bug.  See comment above. */
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		*(volatile unsigned long *)KSEG1;
 
 		a = addr & ~(dc_lsize - 1);
@@ -2108,9 +2006,9 @@
 			if (a == end) break;
 			a += dc_lsize;
 		}
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
-	bcops->bc_wback_inv(addr, size);
+	bc_wback_inv(addr, size);
 }
 
 static void
@@ -2142,7 +2040,7 @@
 		flush_cache_all();
 	} else {
 		/* Workaround for R4600 bug.  See comment above. */
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		*(volatile unsigned long *)KSEG1;
 
 		a = addr & ~(dc_lsize - 1);
@@ -2152,10 +2050,10 @@
 			if (a == end) break;
 			a += dc_lsize;
 		}
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
 
-	bcops->bc_inv(addr, size);
+	bc_inv(addr, size);
 }
 
 static void
@@ -2237,7 +2135,7 @@
 	printk("[tlball]");
 #endif
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	/* Save old context and create impossible VPN2 value */
 	old_ctx = (get_entryhi() & 0xff);
 	set_entryhi(KSEG0);
@@ -2257,7 +2155,7 @@
 	}
 	BARRIER;
 	set_entryhi(old_ctx);
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
@@ -2268,11 +2166,11 @@
 #ifdef DEBUG_TLB
 		printk("[tlbmm<%d>]", mm->context);
 #endif
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		get_new_mmu_context(mm, asid_cache);
 		if (mm == current->active_mm)
 			set_entryhi(mm->context & 0xff);
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
 }
 
@@ -2287,7 +2185,7 @@
 		printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
 		       start, end);
 #endif
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 		size = (size + 1) >> 1;
 		if(size <= NTLB_ENTRIES_HALF) {
@@ -2321,7 +2219,7 @@
 			if (mm == current->active_mm)
 				set_entryhi(mm->context & 0xff);
 		}
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
 }
 
@@ -2336,7 +2234,7 @@
 #endif
 		newpid = (vma->vm_mm->context & 0xff);
 		page &= (PAGE_MASK << 1);
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		oldpid = (get_entryhi() & 0xff);
 		set_entryhi(page | newpid);
 		BARRIER;
@@ -2354,15 +2252,10 @@
 	finish:
 		BARRIER;
 		set_entryhi(oldpid);
-		restore_flags(flags);
+		__restore_flags(flags);
 	}
 }
 
-/* Load a new root pointer into the TLB. */
-void load_pgd(unsigned long pg_dir)
-{
-}
-
 void pgd_init(unsigned long page)
 {
 	unsigned long *p = (unsigned long *) page;
@@ -2380,12 +2273,6 @@
 	}
 }
 
-#ifdef DEBUG_TLBUPDATE
-static unsigned long ehi_debug[NTLB_ENTRIES];
-static unsigned long el0_debug[NTLB_ENTRIES];
-static unsigned long el1_debug[NTLB_ENTRIES];
-#endif
-
 /* We will need multiple versions of update_mmu_cache(), one that just
  * updates the TLB with the new pte(s), and another which also checks
  * for the R4k "end of page" hardware bug and does the needy.
@@ -2414,7 +2301,7 @@
 	}
 #endif
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	address &= (PAGE_MASK << 1);
 	set_entryhi(address | (pid));
 	pgdp = pgd_offset(vma->vm_mm, address);
@@ -2437,7 +2324,7 @@
 	BARRIER;
 	set_entryhi(pid);
 	BARRIER;
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 #if 0
@@ -2450,7 +2337,7 @@
 	pte_t *ptep;
 	int idx;
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	address &= (PAGE_MASK << 1);
 	set_entryhi(address | (get_entryhi() & 0xff));
 	pgdp = pgd_offset(vma->vm_mm, address);
@@ -2466,7 +2353,7 @@
 	else
 		tlb_write_indexed();
 	BARRIER;
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 #endif
 
@@ -2503,7 +2390,7 @@
         unsigned long old_pagemask;
         unsigned long old_ctx;
 
-        save_and_cli(flags);
+        __save_and_cli(flags);
         /* Save old context and create impossible VPN2 value */
         old_ctx = (get_entryhi() & 0xff);
         old_pagemask = get_pagemask();
@@ -2523,7 +2410,7 @@
         BARRIER;    
         set_pagemask (old_pagemask);
         flush_tlb_all();    
-        restore_flags(flags);
+        __restore_flags(flags);
 }
 
 /* Detect and size the various r4k caches. */
@@ -2532,7 +2419,7 @@
 	icache_size = 1 << (12 + ((config >> 9) & 7));
 	ic_lsize = 16 << ((config >> 5) & 1);
 
-	printk("Primary instruction cache %dkb, linesize %d bytes)\n",
+	printk("Primary instruction cache %dkb, linesize %d bytes.\n",
 	       icache_size >> 10, ic_lsize);
 }
 
@@ -2541,7 +2428,7 @@
 	dcache_size = 1 << (12 + ((config >> 6) & 7));
 	dc_lsize = 16 << ((config >> 4) & 1);
 
-	printk("Primary data cache %dkb, linesize %d bytes)\n",
+	printk("Primary data cache %dkb, linesize %d bytes.\n",
 	       dcache_size >> 10, dc_lsize);
 }
 
@@ -2583,7 +2470,7 @@
 	/* This is such a bitch, you'd think they would make it
 	 * easy to do this.  Away you daemons of stupidity!
 	 */
-	save_and_cli(flags);
+	__save_and_cli(flags);
 
 	/* Fill each size-multiple cache line with a valid tag. */
 	pow2 = (64 * 1024);
@@ -2627,9 +2514,9 @@
 			break;
 		pow2 <<= 1;
 	}
-	restore_flags(flags);
+	__restore_flags(flags);
 	addr -= begin;
-	printk("Secondary cache sized at %dK linesize %d\n",
+	printk("Secondary cache sized at %dK linesize %d bytes.\n",
 	       (int) (addr >> 10), sc_lsize);
 	scache_size = addr;
 	return 1;
@@ -2647,27 +2534,33 @@
 		_flush_cache_mm = r4k_flush_cache_mm_d16i16;
 		_flush_cache_range = r4k_flush_cache_range_d16i16;
 		_flush_cache_page = r4k_flush_cache_page_d16i16;
-		_flush_page_to_ram = r4k_flush_page_to_ram_d16i16;
+		_flush_page_to_ram = r4k_flush_page_to_ram_d16;
 		break;
 	case 32:
 		prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0;
 		if (prid == 0x2010) {			/* R4600 V1.7 */
 			_clear_page = r4k_clear_page_r4600_v1;
 			_copy_page = r4k_copy_page_r4600_v1;
+			_flush_page_to_ram = r4k_flush_page_to_ram_d32_r4600;
 		} else if (prid == 0x2020) {		/* R4600 V2.0 */
 			_clear_page = r4k_clear_page_r4600_v2;
 			_copy_page = r4k_copy_page_r4600_v2;
+			_flush_page_to_ram = r4k_flush_page_to_ram_d32;
 		} else {
 			_clear_page = r4k_clear_page_d32;
 			_copy_page = r4k_copy_page_d32;
+			_flush_page_to_ram = r4k_flush_page_to_ram_d32;
 		}
 		_flush_cache_all = r4k_flush_cache_all_d32i32;
 		_flush_cache_mm = r4k_flush_cache_mm_d32i32;
 		_flush_cache_range = r4k_flush_cache_range_d32i32;
 		_flush_cache_page = r4k_flush_cache_page_d32i32;
-		_flush_page_to_ram = r4k_flush_page_to_ram_d32i32;
 		break;
 	}
+	___flush_cache_all = _flush_cache_all;
+
+	_flush_icache_page = r4k_flush_icache_page_p;
+
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc;
 	_dma_cache_wback = r4k_dma_cache_wback;
 	_dma_cache_inv = r4k_dma_cache_inv_pc;
@@ -2683,11 +2576,11 @@
 			_flush_cache_mm = r4k_flush_cache_mm_s16d16i16;
 			_flush_cache_range = r4k_flush_cache_range_s16d16i16;
 			_flush_cache_page = r4k_flush_cache_page_s16d16i16;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16;
 			break;
 		case 32:
 			panic("Invalid cache configuration detected");
 		};
+		_flush_page_to_ram = r4k_flush_page_to_ram_s16;
 		_clear_page = r4k_clear_page_s16;
 		_copy_page = r4k_copy_page_s16;
 		break;
@@ -2698,16 +2591,15 @@
 			_flush_cache_mm = r4k_flush_cache_mm_s32d16i16;
 			_flush_cache_range = r4k_flush_cache_range_s32d16i16;
 			_flush_cache_page = r4k_flush_cache_page_s32d16i16;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16;
 			break;
 		case 32:
 			_flush_cache_all = r4k_flush_cache_all_s32d32i32;
 			_flush_cache_mm = r4k_flush_cache_mm_s32d32i32;
 			_flush_cache_range = r4k_flush_cache_range_s32d32i32;
 			_flush_cache_page = r4k_flush_cache_page_s32d32i32;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32;
 			break;
 		};
+		_flush_page_to_ram = r4k_flush_page_to_ram_s32;
 		_clear_page = r4k_clear_page_s32;
 		_copy_page = r4k_copy_page_s32;
 		break;
@@ -2718,16 +2610,15 @@
 			_flush_cache_mm = r4k_flush_cache_mm_s64d16i16;
 			_flush_cache_range = r4k_flush_cache_range_s64d16i16;
 			_flush_cache_page = r4k_flush_cache_page_s64d16i16;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16;
 			break;
 		case 32:
 			_flush_cache_all = r4k_flush_cache_all_s64d32i32;
 			_flush_cache_mm = r4k_flush_cache_mm_s64d32i32;
 			_flush_cache_range = r4k_flush_cache_range_s64d32i32;
 			_flush_cache_page = r4k_flush_cache_page_s64d32i32;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32;
 			break;
 		};
+		_flush_page_to_ram = r4k_flush_page_to_ram_s64;
 		_clear_page = r4k_clear_page_s64;
 		_copy_page = r4k_copy_page_s64;
 		break;
@@ -2738,20 +2629,21 @@
 			_flush_cache_mm = r4k_flush_cache_mm_s128d16i16;
 			_flush_cache_range = r4k_flush_cache_range_s128d16i16;
 			_flush_cache_page = r4k_flush_cache_page_s128d16i16;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16;
 			break;
 		case 32:
 			_flush_cache_all = r4k_flush_cache_all_s128d32i32;
 			_flush_cache_mm = r4k_flush_cache_mm_s128d32i32;
 			_flush_cache_range = r4k_flush_cache_range_s128d32i32;
 			_flush_cache_page = r4k_flush_cache_page_s128d32i32;
-			_flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32;
 			break;
 		};
+		_flush_page_to_ram = r4k_flush_page_to_ram_s128;
 		_clear_page = r4k_clear_page_s128;
 		_copy_page = r4k_copy_page_s128;
 		break;
 	}
+	___flush_cache_all = _flush_cache_all;
+	_flush_icache_page = r4k_flush_icache_page_s;
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc;
 	_dma_cache_wback = r4k_dma_cache_wback;
 	_dma_cache_inv = r4k_dma_cache_inv_sc;
@@ -2782,13 +2674,17 @@
 
 	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
 
-	set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+#ifdef CONFIG_MIPS_UNCACHED
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+#else
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+#endif
 
 	probe_icache(config);
 	probe_dcache(config);
 	setup_scache(config);
 
-	switch(mips_cputype) {
+	switch(mips_cpu.cputype) {
 	case CPU_R4600:			/* QED style two way caches? */
 	case CPU_R4700:
 	case CPU_R5000:
@@ -2797,11 +2693,12 @@
 	}
 
 	_flush_cache_sigtramp = r4k_flush_cache_sigtramp;
+	_flush_icache_range = r4k_flush_icache_range;	/* Ouch */
 	if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) {
 		_flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp;
 	}
 
-	flush_cache_all();
+	__flush_cache_all();
 	write_32bit_cp0_register(CP0_WIRED, 0);
 
 	/*
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/r5432.c linux/arch/mips/mm/r5432.c
--- v2.4.6/linux/arch/mips/mm/r5432.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mm/r5432.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,868 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * r5432.c: NEC Vr5432 processor.  We cannot use r4xx0.c because of
+ *      its unique way-selection method for indexed operations.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 2000 Jun Sun (jsun@mvista.com)
+ *
+ */
+
+/*
+ * [jsun]
+ * In a sense, this is really silly.  We cannot re-use r4xx0.c because
+ * the lowest-level indexed cache operation does not take way-selection
+ * into account.  So all what I am doing here is to copy all the funcs
+ * and macros (in r4kcache.h) relavent to R5432 to this file, and then
+ * modify a few indexed cache operations.  *sigh*
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/bcache.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/bootinfo.h>
+#include <asm/mmu_context.h>
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+				     "nop; nop; nop; nop; nop; nop;\n\t" \
+				     ".set reorder\n\t")
+
+#include <asm/asm.h>
+#include <asm/cacheops.h>
+
+#undef DEBUG_CACHE
+
+/* Primary cache parameters. */
+static int icache_size, dcache_size; /* Size in bytes */
+static int ic_lsize, dc_lsize;       /* LineSize in bytes */
+
+
+/* -------------------------------------------------------------------- */
+/* #include <asm/r4kcache.h> */
+
+extern inline void flush_icache_line_indexed(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		"cache %1, 1(%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Index_Invalidate_I));
+}
+
+extern inline void flush_dcache_line_indexed(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		"cache %1, 1(%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Index_Writeback_Inv_D));
+}
+
+extern inline void flush_icache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_I));
+}
+
+extern inline void flush_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Writeback_Inv_D));
+}
+
+extern inline void invalidate_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_D));
+}
+
+
+/*
+ * The next two are for badland addresses like signal trampolines.
+ */
+extern inline void protected_flush_icache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set mips0\n\t"
+		".set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		STR(PTR)"\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_I));
+}
+
+extern inline void protected_writeback_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set mips0\n\t"
+		".set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		STR(PTR)"\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr),
+		  "i" (Hit_Writeback_D));
+}
+
+
+#define cache32_unroll32(base,op)				\
+	__asm__ __volatile__("					\
+		.set noreorder;					\
+		.set mips3;					\
+		cache %1, 0x000(%0); cache %1, 0x020(%0);	\
+		cache %1, 0x040(%0); cache %1, 0x060(%0);	\
+		cache %1, 0x080(%0); cache %1, 0x0a0(%0);	\
+		cache %1, 0x0c0(%0); cache %1, 0x0e0(%0);	\
+		cache %1, 0x100(%0); cache %1, 0x120(%0);	\
+		cache %1, 0x140(%0); cache %1, 0x160(%0);	\
+		cache %1, 0x180(%0); cache %1, 0x1a0(%0);	\
+		cache %1, 0x1c0(%0); cache %1, 0x1e0(%0);	\
+		cache %1, 0x200(%0); cache %1, 0x220(%0);	\
+		cache %1, 0x240(%0); cache %1, 0x260(%0);	\
+		cache %1, 0x280(%0); cache %1, 0x2a0(%0);	\
+		cache %1, 0x2c0(%0); cache %1, 0x2e0(%0);	\
+		cache %1, 0x300(%0); cache %1, 0x320(%0);	\
+		cache %1, 0x340(%0); cache %1, 0x360(%0);	\
+		cache %1, 0x380(%0); cache %1, 0x3a0(%0);	\
+		cache %1, 0x3c0(%0); cache %1, 0x3e0(%0);	\
+		.set mips0;					\
+		.set reorder"					\
+		:						\
+		: "r" (base),					\
+		  "i" (op));
+
+extern inline void blast_dcache32(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + dcache_size/2);
+
+	while(start < end) {
+		cache32_unroll32(start,Index_Writeback_Inv_D);
+		cache32_unroll32(start+1,Index_Writeback_Inv_D);
+		start += 0x400;
+	}
+}
+
+extern inline void blast_dcache32_page(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = (start + PAGE_SIZE);
+
+	while(start < end) {
+		cache32_unroll32(start,Hit_Writeback_Inv_D);
+		start += 0x400;
+	}
+}
+
+extern inline void blast_dcache32_page_indexed(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = (start + PAGE_SIZE);
+
+	while(start < end) {
+		cache32_unroll32(start,Index_Writeback_Inv_D);
+		cache32_unroll32(start+1,Index_Writeback_Inv_D);
+		start += 0x400;
+	}
+}
+
+extern inline void blast_icache32(void)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + icache_size/2);
+
+	while(start < end) {
+		cache32_unroll32(start,Index_Invalidate_I);
+		cache32_unroll32(start+1,Index_Invalidate_I);
+		start += 0x400;
+	}
+}
+
+extern inline void blast_icache32_page(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = (start + PAGE_SIZE);
+
+	while(start < end) {
+		cache32_unroll32(start,Hit_Invalidate_I);
+		start += 0x400;
+	}
+}
+
+extern inline void blast_icache32_page_indexed(unsigned long page)
+{
+	unsigned long start = page;
+	unsigned long end = (start + PAGE_SIZE);
+
+	while(start < end) {
+		cache32_unroll32(start,Index_Invalidate_I);
+		cache32_unroll32(start+1,Index_Invalidate_I);
+		start += 0x400;
+	}
+}
+
+/* -------------------------------------------------------------------- */
+
+static void r5432_clear_page_d32(void * page)
+{
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"daddiu\t$1,%0,%2\n"
+		"1:\tcache\t%3,(%0)\n\t"
+		"sd\t$0,(%0)\n\t"
+		"sd\t$0,8(%0)\n\t"
+		"sd\t$0,16(%0)\n\t"
+		"sd\t$0,24(%0)\n\t"
+		"daddiu\t%0,64\n\t"
+		"cache\t%3,-32(%0)\n\t"
+		"sd\t$0,-32(%0)\n\t"
+		"sd\t$0,-24(%0)\n\t"
+		"sd\t$0,-16(%0)\n\t"
+		"bne\t$1,%0,1b\n\t"
+		"sd\t$0,-8(%0)\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+		:"=r" (page)
+		:"0" (page),
+		 "I" (PAGE_SIZE),
+		 "i" (Create_Dirty_Excl_D)
+		:"$1","memory");
+}
+
+
+
+/*
+ * This is still inefficient.  We only can do better if we know the
+ * virtual address where the copy will be accessed.
+ */
+
+static void r5432_copy_page_d32(void * to, void * from)
+{
+	unsigned long dummy1, dummy2;
+	unsigned long reg1, reg2, reg3, reg4;
+
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"daddiu\t$1,%0,%8\n"
+		"1:\tcache\t%9,(%0)\n\t"
+		"lw\t%2,(%1)\n\t"
+		"lw\t%3,4(%1)\n\t"
+		"lw\t%4,8(%1)\n\t"
+		"lw\t%5,12(%1)\n\t"
+		"sw\t%2,(%0)\n\t"
+		"sw\t%3,4(%0)\n\t"
+		"sw\t%4,8(%0)\n\t"
+		"sw\t%5,12(%0)\n\t"
+		"lw\t%2,16(%1)\n\t"
+		"lw\t%3,20(%1)\n\t"
+		"lw\t%4,24(%1)\n\t"
+		"lw\t%5,28(%1)\n\t"
+		"sw\t%2,16(%0)\n\t"
+		"sw\t%3,20(%0)\n\t"
+		"sw\t%4,24(%0)\n\t"
+		"sw\t%5,28(%0)\n\t"
+		"cache\t%9,32(%0)\n\t"
+		"daddiu\t%0,64\n\t"
+		"daddiu\t%1,64\n\t"
+		"lw\t%2,-32(%1)\n\t"
+		"lw\t%3,-28(%1)\n\t"
+		"lw\t%4,-24(%1)\n\t"
+		"lw\t%5,-20(%1)\n\t"
+		"sw\t%2,-32(%0)\n\t"
+		"sw\t%3,-28(%0)\n\t"
+		"sw\t%4,-24(%0)\n\t"
+		"sw\t%5,-20(%0)\n\t"
+		"lw\t%2,-16(%1)\n\t"
+		"lw\t%3,-12(%1)\n\t"
+		"lw\t%4,-8(%1)\n\t"
+		"lw\t%5,-4(%1)\n\t"
+		"sw\t%2,-16(%0)\n\t"
+		"sw\t%3,-12(%0)\n\t"
+		"sw\t%4,-8(%0)\n\t"
+		"bne\t$1,%0,1b\n\t"
+		"sw\t%5,-4(%0)\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+		:"=r" (dummy1), "=r" (dummy2),
+		 "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
+		:"0" (to), "1" (from),
+		 "I" (PAGE_SIZE),
+		 "i" (Create_Dirty_Excl_D));
+}
+
+
+/*
+ * If you think for one second that this stuff coming up is a lot
+ * of bulky code eating too many kernel cache lines.  Think _again_.
+ *
+ * Consider:
+ * 1) Taken branches have a 3 cycle penalty on R4k
+ * 2) The branch itself is a real dead cycle on even R4600/R5000.
+ * 3) Only one of the following variants of each type is even used by
+ *    the kernel based upon the cache parameters we detect at boot time.
+ *
+ * QED.
+ */
+
+static inline void r5432_flush_cache_all_d32i32(void)
+{
+	blast_dcache32(); blast_icache32();
+}
+
+static void r5432_flush_cache_range_d32i32(struct mm_struct *mm,
+					 unsigned long start,
+					 unsigned long end)
+{
+	if (mm->context != 0) {
+#ifdef DEBUG_CACHE
+		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
+#endif
+		blast_dcache32(); blast_icache32();
+	}
+}
+
+/*
+ * On architectures like the Sparc, we could get rid of lines in
+ * the cache created only by a certain context, but on the MIPS
+ * (and actually certain Sparc's) we cannot.
+ */
+static void r5432_flush_cache_mm_d32i32(struct mm_struct *mm)
+{
+	if (mm->context != 0) {
+#ifdef DEBUG_CACHE
+		printk("cmm[%d]", (int)mm->context);
+#endif
+		r5432_flush_cache_all_d32i32();
+	}
+}
+
+static void r5432_flush_cache_page_d32i32(struct vm_area_struct *vma,
+					unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	/*
+	 * If ownes no valid ASID yet, cannot possibly have gotten
+	 * this page into the cache.
+	 */
+	if (mm->context == 0)
+		return;
+
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+	page &= PAGE_MASK;
+	pgdp = pgd_offset(mm, page);
+	pmdp = pmd_offset(pgdp, page);
+	ptep = pte_offset(pmdp, page);
+
+	/*
+	 * If the page isn't marked valid, the page cannot possibly be
+	 * in the cache.
+	 */
+	if (!(pte_val(*ptep) & _PAGE_PRESENT))
+		return;
+
+	/*
+	 * Doing flushes for another ASID than the current one is
+	 * too difficult since stupid R4k caches do a TLB translation
+	 * for every cache flush operation.  So we do indexed flushes
+	 * in that case, which doesn't overly flush the cache too much.
+	 */
+	if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
+		blast_dcache32_page(page);
+	} else {
+		/*
+		 * Do indexed flush, too much work to get the (possible)
+		 * tlb refills to work correctly.
+		 */
+		page = (KSEG0 + (page & (dcache_size - 1)));
+		blast_dcache32_page_indexed(page);
+	}
+}
+
+
+/* If the addresses passed to these routines are valid, they are
+ * either:
+ *
+ * 1) In KSEG0, so we can do a direct flush of the page.
+ * 2) In KSEG2, and since every process can translate those
+ *    addresses all the time in kernel mode we can do a direct
+ *    flush.
+ * 3) In KSEG1, no flush necessary.
+ */
+static void r5432_flush_page_to_ram_d32(struct page *page)
+{
+	blast_dcache32_page((unsigned long)page_address(page));
+}
+
+static void 
+r5432_flush_icache_range(unsigned long start, unsigned long end)
+{
+	r5432_flush_cache_all_d32i32();
+}
+
+/*
+ * Ok, this seriously sucks.  We use them to flush a user page but don't
+ * know the virtual address, so we have to blast away the whole icache
+ * which is significantly more expensive than the real thing.
+ */
+static void
+r5432_flush_icache_page_i32(struct vm_area_struct *vma, struct page *page)
+{
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
+
+	r5432_flush_cache_all_d32i32();
+}
+
+/*
+ * Writeback and invalidate the primary cache dcache before DMA.
+ */
+static void
+r5432_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= dcache_size) {
+		flush_cache_all();
+	} else {
+		a = addr & ~(dc_lsize - 1);
+		end = (addr + size) & ~(dc_lsize - 1);
+		while (1) {
+			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+			if (a == end) break;
+			a += dc_lsize;
+		}
+	}
+	bc_wback_inv(addr, size);
+}
+
+static void
+r5432_dma_cache_inv_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	if (size >= dcache_size) {
+		flush_cache_all();
+	} else {
+		a = addr & ~(dc_lsize - 1);
+		end = (addr + size) & ~(dc_lsize - 1);
+		while (1) {
+			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+			if (a == end) break;
+			a += dc_lsize;
+		}
+	}
+
+	bc_inv(addr, size);
+}
+
+static void
+r5432_dma_cache_wback(unsigned long addr, unsigned long size)
+{
+	panic("r5432_dma_cache called - should not happen.\n");
+}
+
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case.  Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
+static void r5432_flush_cache_sigtramp(unsigned long addr)
+{
+	unsigned long daddr, iaddr;
+
+	daddr = addr & ~(dc_lsize - 1);
+	protected_writeback_dcache_line(daddr);
+	protected_writeback_dcache_line(daddr + dc_lsize);
+	iaddr = addr & ~(ic_lsize - 1);
+	protected_flush_icache_line(iaddr);
+	protected_flush_icache_line(iaddr + ic_lsize);
+}
+
+#undef DEBUG_TLB
+#undef DEBUG_TLBUPDATE
+
+#define NTLB_ENTRIES       48  /* Fixed on all R4XX0 variants... */
+
+#define NTLB_ENTRIES_HALF  24  /* Fixed on all R4XX0 variants... */
+
+void flush_tlb_all(void)
+{
+	unsigned long old_ctx;
+	int entry;
+	unsigned long flags;
+
+#ifdef DEBUG_TLB
+	printk("[tlball]");
+#endif
+
+	__save_and_cli(flags);
+	/* Save old context and create impossible VPN2 value */
+	old_ctx = (get_entryhi() & 0xff);
+	set_entryhi(KSEG0);
+	set_entrylo0(0);
+	set_entrylo1(0);
+	BARRIER;
+
+	entry = get_wired();
+
+	/* Blast 'em all away. */
+	while(entry < NTLB_ENTRIES) {
+		set_index(entry);
+		BARRIER;
+		tlb_write_indexed();
+		BARRIER;
+		entry++;
+	}
+	BARRIER;
+	set_entryhi(old_ctx);
+	__restore_flags(flags);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	if (mm->context != 0) {
+		unsigned long flags;
+
+#ifdef DEBUG_TLB
+		printk("[tlbmm<%d>]", mm->context);
+#endif
+		__save_and_cli(flags);
+		get_new_mmu_context(mm, asid_cache);
+		if (mm == current->active_mm)
+			set_entryhi(mm->context & 0xff);
+		__restore_flags(flags);
+	}
+}
+
+void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				unsigned long end)
+{
+	if(mm->context != 0) {
+		unsigned long flags;
+		int size;
+
+#ifdef DEBUG_TLB
+		printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
+		       start, end);
+#endif
+		__save_and_cli(flags);
+		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+		size = (size + 1) >> 1;
+		if(size <= NTLB_ENTRIES_HALF) {
+			int oldpid = (get_entryhi() & 0xff);
+			int newpid = (mm->context & 0xff);
+
+			start &= (PAGE_MASK << 1);
+			end += ((PAGE_SIZE << 1) - 1);
+			end &= (PAGE_MASK << 1);
+			while(start < end) {
+				int idx;
+
+				set_entryhi(start | newpid);
+				start += (PAGE_SIZE << 1);
+				BARRIER;
+				tlb_probe();
+				BARRIER;
+				idx = get_index();
+				set_entrylo0(0);
+				set_entrylo1(0);
+				set_entryhi(KSEG0);
+				BARRIER;
+				if(idx < 0)
+					continue;
+				tlb_write_indexed();
+				BARRIER;
+			}
+			set_entryhi(oldpid);
+		} else {
+			get_new_mmu_context(mm, asid_cache);
+			if (mm == current->active_mm)
+				set_entryhi(mm->context & 0xff);
+		}
+		__restore_flags(flags);
+	}
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	if (vma->vm_mm->context != 0) {
+		unsigned long flags;
+		int oldpid, newpid, idx;
+
+#ifdef DEBUG_TLB
+		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+#endif
+		newpid = (vma->vm_mm->context & 0xff);
+		page &= (PAGE_MASK << 1);
+		__save_and_cli(flags);
+		oldpid = (get_entryhi() & 0xff);
+		set_entryhi(page | newpid);
+		BARRIER;
+		tlb_probe();
+		BARRIER;
+		idx = get_index();
+		set_entrylo0(0);
+		set_entrylo1(0);
+		set_entryhi(KSEG0);
+		if(idx < 0)
+			goto finish;
+		BARRIER;
+		tlb_write_indexed();
+
+	finish:
+		BARRIER;
+		set_entryhi(oldpid);
+		__restore_flags(flags);
+	}
+}
+
+void pgd_init(unsigned long page)
+{
+	unsigned long *p = (unsigned long *) page;
+	int i;
+
+	for(i = 0; i < USER_PTRS_PER_PGD; i+=8) {
+		p[i + 0] = (unsigned long) invalid_pte_table;
+		p[i + 1] = (unsigned long) invalid_pte_table;
+		p[i + 2] = (unsigned long) invalid_pte_table;
+		p[i + 3] = (unsigned long) invalid_pte_table;
+		p[i + 4] = (unsigned long) invalid_pte_table;
+		p[i + 5] = (unsigned long) invalid_pte_table;
+		p[i + 6] = (unsigned long) invalid_pte_table;
+		p[i + 7] = (unsigned long) invalid_pte_table;
+	}
+}
+
+/* We will need multiple versions of update_mmu_cache(), one that just
+ * updates the TLB with the new pte(s), and another which also checks
+ * for the R4k "end of page" hardware bug and does the needy.
+ */
+void update_mmu_cache(struct vm_area_struct * vma,
+				 unsigned long address, pte_t pte)
+{
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	int idx, pid;
+
+	/*
+	 * Handle debugger faulting in for debugee.
+	 */
+	if (current->active_mm != vma->vm_mm)
+		return;
+
+	pid = get_entryhi() & 0xff;
+
+#ifdef DEBUG_TLB
+	if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) {
+		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n",
+		       (int) (vma->vm_mm->context & 0xff), pid);
+	}
+#endif
+
+	__save_and_cli(flags);
+	address &= (PAGE_MASK << 1);
+	set_entryhi(address | (pid));
+	pgdp = pgd_offset(vma->vm_mm, address);
+	BARRIER;
+	tlb_probe();
+	BARRIER;
+	pmdp = pmd_offset(pgdp, address);
+	idx = get_index();
+	ptep = pte_offset(pmdp, address);
+	BARRIER;
+	set_entrylo0(pte_val(*ptep++) >> 6);
+	set_entrylo1(pte_val(*ptep) >> 6);
+	set_entryhi(address | (pid));
+	BARRIER;
+	if(idx < 0) {
+		tlb_write_random();
+	} else {
+		tlb_write_indexed();
+	}
+	BARRIER;
+	set_entryhi(pid);
+	BARRIER;
+	__restore_flags(flags);
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	/* Saved main processor registers. */
+	printk("$0 : %08lx %08lx %08lx %08lx\n",
+	       0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
+	printk("$4 : %08lx %08lx %08lx %08lx\n",
+               regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
+	printk("$8 : %08lx %08lx %08lx %08lx\n",
+	       regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
+	printk("$12: %08lx %08lx %08lx %08lx\n",
+               regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
+	printk("$16: %08lx %08lx %08lx %08lx\n",
+	       regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
+	printk("$20: %08lx %08lx %08lx %08lx\n",
+               regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
+	printk("$24: %08lx %08lx\n",
+	       regs->regs[24], regs->regs[25]);
+	printk("$28: %08lx %08lx %08lx %08lx\n",
+	       regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
+
+	/* Saved cp0 registers. */
+	printk("epc   : %08lx\nStatus: %08lx\nCause : %08lx\n",
+	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+			
+void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+		     unsigned long entryhi, unsigned long pagemask)
+{
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        __save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        set_wired (wired + 1);
+        set_index (wired);
+        BARRIER;    
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;    
+        tlb_write_indexed();
+        BARRIER;    
+    
+        set_entryhi(old_ctx);
+        BARRIER;    
+        set_pagemask (old_pagemask);
+        flush_tlb_all();    
+        __restore_flags(flags);
+}
+
+/* Detect and size the various r4k caches. */
+static void __init probe_icache(unsigned long config)
+{
+	icache_size = 1 << (12 + ((config >> 9) & 7));
+	ic_lsize = 16 << ((config >> 5) & 1);
+
+	printk("Primary instruction cache %dkb, linesize %d bytes.\n",
+	       icache_size >> 10, ic_lsize);
+}
+
+static void __init probe_dcache(unsigned long config)
+{
+	dcache_size = 1 << (12 + ((config >> 6) & 7));
+	dc_lsize = 16 << ((config >> 4) & 1);
+
+	printk("Primary data cache %dkb, linesize %d bytes.\n",
+	       dcache_size >> 10, dc_lsize);
+}
+
+
+void __init ld_mmu_r5432(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+
+	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
+
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+
+	probe_icache(config);
+	probe_dcache(config);
+
+	_clear_page = r5432_clear_page_d32;
+	_copy_page = r5432_copy_page_d32;
+	_flush_cache_all = r5432_flush_cache_all_d32i32;
+	___flush_cache_all = r5432_flush_cache_all_d32i32;
+	_flush_page_to_ram = r5432_flush_page_to_ram_d32;
+	_flush_cache_mm = r5432_flush_cache_mm_d32i32;
+	_flush_cache_range = r5432_flush_cache_range_d32i32;
+	_flush_cache_page = r5432_flush_cache_page_d32i32;
+	_flush_icache_page = r5432_flush_icache_page_i32;
+	_dma_cache_wback_inv = r5432_dma_cache_wback_inv_pc;
+	_dma_cache_wback = r5432_dma_cache_wback;
+	_dma_cache_inv = r5432_dma_cache_inv_pc;
+
+	_flush_cache_sigtramp = r5432_flush_cache_sigtramp;
+	_flush_icache_range = r5432_flush_icache_range;	/* Ouch */
+
+	__flush_cache_all();
+	write_32bit_cp0_register(CP0_WIRED, 0);
+
+	/*
+	 * You should never change this register:
+	 *   - On R4600 1.7 the tlbp never hits for pages smaller than
+	 *     the value in the c0_pagemask register.
+	 *   - The entire mm handling assumes the c0_pagemask register to
+	 *     be set for 4kb pages.
+	 */
+	write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
+	flush_tlb_all();
+}
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/rm7k.c linux/arch/mips/mm/rm7k.c
--- v2.4.6/linux/arch/mips/mm/rm7k.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mm/rm7k.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,751 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * r4xx0.c: R4000 processor variant specific MMU/Cache routines.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997, 1998 Ralf Baechle ralf@gnu.org
+ *
+ * To do:
+ *
+ *  - this code is a overbloated pig
+ *  - many of the bug workarounds are not efficient at all, but at
+ *    least they are functional ...
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/bootinfo.h>
+#include <asm/mmu_context.h>
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+				     "nop; nop; nop; nop; nop; nop;\n\t" \
+				     ".set reorder\n\t")
+
+/* Primary cache parameters. */
+static int icache_size, dcache_size; /* Size in bytes */
+
+#define ic_lsize	32		/* Fixed to 32 byte on RM7000  */
+#define dc_lsize	32		/* Fixed to 32 byte on RM7000  */
+#define sc_lsize	32		/* Fixed to 32 byte on RM7000  */
+#define tc_pagesize	(32*128)
+
+/* Secondary cache parameters. */
+#define scache_size	(256*1024)	/* Fixed to 256KiB on RM7000 */
+
+#include <asm/cacheops.h>
+#include <asm/r4kcache.h>
+
+int rm7k_tcache_enabled = 0;
+
+/*
+ * Not added to asm/r4kcache.h because it seems to be RM7000-specific.
+ */
+#define Page_Invalidate_T 0x16
+
+static inline void invalidate_tcache_page(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set\tnoreorder\t\t\t# invalidate_tcache_page\n\t"
+		".set\tmips3\n\t"
+		"cache\t%1, (%0)\n\t"
+		".set\tmips0\n\t"
+		".set\treorder"
+		:
+		: "r" (addr),
+		  "i" (Page_Invalidate_T));
+}
+
+/*
+ * Zero an entire page.  Note that while the RM7000 has a second level cache
+ * it doesn't have a Create_Dirty_Excl_SD operation.
+ */
+static void rm7k_clear_page(void * page)
+{
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"daddiu\t$1,%0,%2\n"
+		"1:\tcache\t%3,(%0)\n\t"
+		"sd\t$0,(%0)\n\t"
+		"sd\t$0,8(%0)\n\t"
+		"sd\t$0,16(%0)\n\t"
+		"sd\t$0,24(%0)\n\t"
+		"daddiu\t%0,64\n\t"
+		"cache\t%3,-32(%0)\n\t"
+		"sd\t$0,-32(%0)\n\t"
+		"sd\t$0,-24(%0)\n\t"
+		"sd\t$0,-16(%0)\n\t"
+		"bne\t$1,%0,1b\n\t"
+		"sd\t$0,-8(%0)\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+		:"=r" (page)
+		:"0" (page),
+		 "I" (PAGE_SIZE),
+		 "i" (Create_Dirty_Excl_D)
+		:"$1","memory");
+}
+
+
+/*
+ * Copy an entire page.  Note that while the RM7000 has a second level cache
+ * it doesn't have a Create_Dirty_Excl_SD operation.
+ */
+static void rm7k_copy_page(void * to, void * from)
+{
+	unsigned long dummy1, dummy2;
+	unsigned long reg1, reg2, reg3, reg4;
+
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"daddiu\t$1,%0,%8\n"
+		"1:\tcache\t%9,(%0)\n\t"
+		"lw\t%2,(%1)\n\t"
+		"lw\t%3,4(%1)\n\t"
+		"lw\t%4,8(%1)\n\t"
+		"lw\t%5,12(%1)\n\t"
+		"sw\t%2,(%0)\n\t"
+		"sw\t%3,4(%0)\n\t"
+		"sw\t%4,8(%0)\n\t"
+		"sw\t%5,12(%0)\n\t"
+		"lw\t%2,16(%1)\n\t"
+		"lw\t%3,20(%1)\n\t"
+		"lw\t%4,24(%1)\n\t"
+		"lw\t%5,28(%1)\n\t"
+		"sw\t%2,16(%0)\n\t"
+		"sw\t%3,20(%0)\n\t"
+		"sw\t%4,24(%0)\n\t"
+		"sw\t%5,28(%0)\n\t"
+		"cache\t%9,32(%0)\n\t"
+		"daddiu\t%0,64\n\t"
+		"daddiu\t%1,64\n\t"
+		"lw\t%2,-32(%1)\n\t"
+		"lw\t%3,-28(%1)\n\t"
+		"lw\t%4,-24(%1)\n\t"
+		"lw\t%5,-20(%1)\n\t"
+		"sw\t%2,-32(%0)\n\t"
+		"sw\t%3,-28(%0)\n\t"
+		"sw\t%4,-24(%0)\n\t"
+		"sw\t%5,-20(%0)\n\t"
+		"lw\t%2,-16(%1)\n\t"
+		"lw\t%3,-12(%1)\n\t"
+		"lw\t%4,-8(%1)\n\t"
+		"lw\t%5,-4(%1)\n\t"
+		"sw\t%2,-16(%0)\n\t"
+		"sw\t%3,-12(%0)\n\t"
+		"sw\t%4,-8(%0)\n\t"
+		"bne\t$1,%0,1b\n\t"
+		"sw\t%5,-4(%0)\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+		:"=r" (dummy1), "=r" (dummy2),
+		 "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
+		:"0" (to), "1" (from),
+		 "I" (PAGE_SIZE),
+		 "i" (Create_Dirty_Excl_D));
+}
+
+static void __flush_cache_all_d32i32(void)
+{
+	blast_dcache32();
+	blast_icache32();
+}
+
+static inline void rm7k_flush_cache_all_d32i32(void)
+{
+	/* Yes! Caches that don't suck ...  */
+}
+
+static void rm7k_flush_cache_range_d32i32(struct mm_struct *mm,
+					 unsigned long start,
+					 unsigned long end)
+{
+	/* RM7000 caches are sane ...  */
+}
+
+static void rm7k_flush_cache_mm_d32i32(struct mm_struct *mm)
+{
+	/* RM7000 caches are sane ...  */
+}
+
+static void rm7k_flush_cache_page_d32i32(struct vm_area_struct *vma,
+					unsigned long page)
+{
+	/* RM7000 caches are sane ...  */
+}
+
+static void rm7k_flush_page_to_ram_d32i32(struct page * page)
+{
+	/* Yes!  Caches that don't suck!  */
+}
+
+static void rm7k_flush_icache_range(unsigned long start, unsigned long end)
+{
+	/*
+	 * FIXME: This is overdoing things and harms performance.
+	 */
+	__flush_cache_all_d32i32();
+}
+
+static void rm7k_flush_icache_page(struct vm_area_struct *vma,
+                                   struct page *page)
+{
+	/*
+	 * FIXME: We should not flush the entire cache but establish some
+	 * temporary mapping and use hit_invalidate operation to flush out
+	 * the line from the cache.
+	 */
+	__flush_cache_all_d32i32();
+}
+
+
+/*
+ * Writeback and invalidate the primary cache dcache before DMA.
+ * (XXX These need to be fixed ...)
+ */
+static void
+rm7k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		flush_dcache_line(a);	/* Hit_Writeback_Inv_D */
+		flush_icache_line(a);	/* Hit_Invalidate_I */
+		flush_scache_line(a);	/* Hit_Writeback_Inv_SD */
+		if (a == end) break;
+		a += sc_lsize;
+	}
+
+	if (!rm7k_tcache_enabled) 
+		return;
+
+	a = addr & ~(tc_pagesize - 1);
+	end = (addr + size) & ~(tc_pagesize - 1);
+	while(1) {
+		invalidate_tcache_page(a);	/* Page_Invalidate_T */
+		if (a == end) break;
+		a += tc_pagesize;
+	}
+}
+	       
+static void
+rm7k_dma_cache_inv(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		invalidate_dcache_line(a);	/* Hit_Invalidate_D */
+		flush_icache_line(a);		/* Hit_Invalidate_I */
+		invalidate_scache_line(a);	/* Hit_Invalidate_SD */
+		if (a == end) break;
+		a += sc_lsize;
+	}
+
+	if (!rm7k_tcache_enabled) 
+		return;
+
+	a = addr & ~(tc_pagesize - 1);
+	end = (addr + size) & ~(tc_pagesize - 1);
+	while(1) {
+		invalidate_tcache_page(a);	/* Page_Invalidate_T */
+		if (a == end) break;
+		a += tc_pagesize;
+	}
+}
+
+static void
+rm7k_dma_cache_wback(unsigned long addr, unsigned long size)
+{
+	panic("rm7k_dma_cache_wback called - should not happen.\n");
+}
+
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case.  Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
+static void rm7k_flush_cache_sigtramp(unsigned long addr)
+{
+	protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+	protected_flush_icache_line(addr & ~(ic_lsize - 1));
+}
+
+/*
+ * Undocumented RM7000:  Bit 29 in the info register of the RM7000 v2.0
+ * indicates if the TLB has 48 or 64 entries.
+ *
+ * 29      1 =>    64 entry JTLB
+ *         0 =>    48 entry JTLB
+ */
+static inline int __attribute__((const)) ntlb_entries(void)
+{
+	if (get_info() & (1 << 29))
+		return 64;
+
+	return 48;
+}
+
+void flush_tlb_all(void)
+{
+	unsigned long flags;
+	unsigned long old_ctx;
+	int entry;
+
+	__save_and_cli(flags);
+	/* Save old context and create impossible VPN2 value */
+	old_ctx = get_entryhi() & 0xff;
+	set_entryhi(KSEG0);
+	set_entrylo0(0);
+	set_entrylo1(0);
+	BARRIER;
+
+	entry = get_wired();
+
+	/* Blast 'em all away. */
+	while (entry < ntlb_entries()) {
+		set_index(entry);
+		BARRIER;
+		tlb_write_indexed();
+		BARRIER;
+		entry++;
+	}
+	BARRIER;
+	set_entryhi(old_ctx);
+	__restore_flags(flags);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	if(mm->context != 0) {
+		unsigned long flags;
+
+		__save_and_cli(flags);
+		get_new_mmu_context(mm, asid_cache);
+		if (mm == current->mm)
+			set_entryhi(mm->context & 0xff);
+		__restore_flags(flags);
+	}
+}
+
+void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				unsigned long end)
+{
+	if(mm->context != 0) {
+		unsigned long flags;
+		int size;
+
+		__save_and_cli(flags);
+		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+		size = (size + 1) >> 1;
+		if (size <= (ntlb_entries() / 2)) {
+			int oldpid = (get_entryhi() & 0xff);
+			int newpid = (mm->context & 0xff);
+
+			start &= (PAGE_MASK << 1);
+			end += ((PAGE_SIZE << 1) - 1);
+			end &= (PAGE_MASK << 1);
+			while(start < end) {
+				int idx;
+
+				set_entryhi(start | newpid);
+				start += (PAGE_SIZE << 1);
+				BARRIER;
+				tlb_probe();
+				BARRIER;
+				idx = get_index();
+				set_entrylo0(0);
+				set_entrylo1(0);
+				set_entryhi(KSEG0);
+				BARRIER;
+				if(idx < 0)
+					continue;
+				tlb_write_indexed();
+				BARRIER;
+			}
+			set_entryhi(oldpid);
+		} else {
+			get_new_mmu_context(mm, asid_cache);
+			if(mm == current->mm)
+				set_entryhi(mm->context & 0xff);
+		}
+		__restore_flags(flags);
+	}
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	if(vma->vm_mm->context != 0) {
+		unsigned long flags;
+		int oldpid, newpid, idx;
+
+		newpid = (vma->vm_mm->context & 0xff);
+		page &= (PAGE_MASK << 1);
+		__save_and_cli(flags);
+		oldpid = (get_entryhi() & 0xff);
+		set_entryhi(page | newpid);
+		BARRIER;
+		tlb_probe();
+		BARRIER;
+		idx = get_index();
+		set_entrylo0(0);
+		set_entrylo1(0);
+		set_entryhi(KSEG0);
+		if(idx < 0)
+			goto finish;
+		BARRIER;
+		tlb_write_indexed();
+
+	finish:
+		BARRIER;
+		set_entryhi(oldpid);
+		__restore_flags(flags);
+	}
+}
+
+void pgd_init(unsigned long page)
+{
+	unsigned long *p = (unsigned long *) page;
+	int i;
+
+	for (i = 0; i < USER_PTRS_PER_PGD; i+=8) {
+		p[i + 0] = (unsigned long) invalid_pte_table;
+		p[i + 1] = (unsigned long) invalid_pte_table;
+		p[i + 2] = (unsigned long) invalid_pte_table;
+		p[i + 3] = (unsigned long) invalid_pte_table;
+		p[i + 4] = (unsigned long) invalid_pte_table;
+		p[i + 5] = (unsigned long) invalid_pte_table;
+		p[i + 6] = (unsigned long) invalid_pte_table;
+		p[i + 7] = (unsigned long) invalid_pte_table;
+	}
+}
+
+/*
+ * We will need multiple versions of update_mmu_cache(), one that just
+ * updates the TLB with the new pte(s), and another which also checks
+ * for the R4k "end of page" hardware bug and does the needy.
+ */
+void update_mmu_cache(struct vm_area_struct * vma,
+				 unsigned long address, pte_t pte)
+{
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	int idx, pid;
+
+	/*
+	 * Handle debugger faulting in for debugee.
+	 */
+	if (current->active_mm != vma->vm_mm)
+		return;
+
+	pid = get_entryhi() & 0xff;
+
+	__save_and_cli(flags);
+	address &= (PAGE_MASK << 1);
+	set_entryhi(address | (pid));
+	pgdp = pgd_offset(vma->vm_mm, address);
+	BARRIER;
+	tlb_probe();
+	BARRIER;
+	pmdp = pmd_offset(pgdp, address);
+	idx = get_index();
+	ptep = pte_offset(pmdp, address);
+	BARRIER;
+	set_entrylo0(pte_val(*ptep++) >> 6);
+	set_entrylo1(pte_val(*ptep) >> 6);
+	set_entryhi(address | (pid));
+	BARRIER;
+	if (idx < 0) {
+		tlb_write_random();
+	} else {
+		tlb_write_indexed();
+	}
+	BARRIER;
+	set_entryhi(pid);
+	BARRIER;
+	__restore_flags(flags);
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	/* Saved main processor registers. */
+	printk(KERN_INFO "$0 : %08lx %08lx %08lx %08lx\n",
+	       0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
+	printk(KERN_INFO "$4 : %08lx %08lx %08lx %08lx\n",
+               regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
+	printk(KERN_INFO "$8 : %08lx %08lx %08lx %08lx\n",
+	       regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
+	printk(KERN_INFO "$12: %08lx %08lx %08lx %08lx\n",
+               regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
+	printk(KERN_INFO "$16: %08lx %08lx %08lx %08lx\n",
+	       regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
+	printk(KERN_INFO "$20: %08lx %08lx %08lx %08lx\n",
+               regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
+	printk(KERN_INFO "$24: %08lx %08lx\n",
+	       regs->regs[24], regs->regs[25]);
+	printk(KERN_INFO "$28: %08lx %08lx %08lx %08lx\n",
+	       regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
+
+	/* Saved cp0 registers. */
+	printk(KERN_INFO "epc   : %08lx\nStatus: %08lx\nCause : %08lx\n",
+	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+
+void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                     unsigned long entryhi, unsigned long pagemask)
+{
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        __save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        set_wired (wired + 1);
+        set_index (wired);
+        BARRIER;    
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;    
+        tlb_write_indexed();
+        BARRIER;    
+    
+        set_entryhi(old_ctx);
+        BARRIER;    
+        set_pagemask (old_pagemask);
+        flush_tlb_all();    
+        __restore_flags(flags);
+}
+
+/* Used for loading TLB entries before trap_init() has started, when we
+   don't actually want to add a wired entry which remains throughout the
+   lifetime of the system */
+
+static int temp_tlb_entry __initdata;
+
+__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
+                               unsigned long entryhi, unsigned long pagemask)
+{
+	int ret = 0;
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        __save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        if (--temp_tlb_entry < wired) {
+		printk(KERN_WARNING "No TLB space left for add_temporary_entry\n");
+		ret = -ENOSPC;
+		goto out;
+	}
+
+        set_index (temp_tlb_entry);
+        BARRIER;    
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;    
+        tlb_write_indexed();
+        BARRIER;    
+    
+        set_entryhi(old_ctx);
+        BARRIER;    
+        set_pagemask (old_pagemask);
+ out:
+        __restore_flags(flags);
+	return ret;
+}
+
+
+
+/* Detect and size the caches. */
+static inline void probe_icache(unsigned long config)
+{
+	icache_size = 1 << (12 + ((config >> 9) & 7));
+
+	printk(KERN_INFO "Primary instruction cache %dKiB.\n", icache_size >> 10);
+}
+
+static inline void probe_dcache(unsigned long config)
+{
+	dcache_size = 1 << (12 + ((config >> 6) & 7));
+
+	printk(KERN_INFO "Primary data cache %dKiB.\n", dcache_size >> 10);
+}
+
+
+/* 
+ * This function is executed in the uncached segment KSEG1.
+ * It must not touch the stack, because the stack pointer still points
+ * into KSEG0. 
+ *
+ * Three options:
+ *	- Write it in assembly and guarantee that we don't use the stack.
+ *	- Disable caching for KSEG0 before calling it.
+ *	- Pray that GCC doesn't randomly start using the stack.
+ *
+ * This being Linux, we obviously take the least sane of those options -
+ * following DaveM's lead in r4xx0.c
+ *
+ * It seems we get our kicks from relying on unguaranteed behaviour in GCC
+ */
+static __init void setup_scache(void)
+{
+	int register i;
+	
+	set_cp0_config(1<<3 /* CONF_SE */);
+
+	set_taglo(0);
+	set_taghi(0);
+	
+	for (i=0; i<scache_size; i+=sc_lsize) {
+		__asm__ __volatile__ (
+		      ".set noreorder\n\t"
+		      ".set mips3\n\t"
+		      "cache %1, (%0)\n\t"
+		      ".set mips0\n\t"
+		      ".set reorder"
+		      :
+		      : "r" (KSEG0ADDR(i)),
+		        "i" (Index_Store_Tag_SD));
+	}
+
+}
+
+static inline void probe_scache(unsigned long config)
+{
+	void (*func)(void) = KSEG1ADDR(&setup_scache);
+
+	if ((config >> 31) & 1)
+		return;
+
+	printk(KERN_INFO "Secondary cache %dKiB, linesize %d bytes.\n",
+	       (scache_size >> 10), sc_lsize);
+
+	if ((config >> 3) & 1)
+		return;
+
+	printk(KERN_INFO "Enabling secondary cache...");
+	func();
+	printk("Done\n");
+}
+ 
+static inline void probe_tcache(unsigned long config)
+{
+	if ((config >> 17) & 1)
+		return;
+
+	/* We can't enable the L3 cache yet. There may be board-specific
+	 * magic necessary to turn it on, and blindly asking the CPU to
+	 * start using it would may give cache errors.
+	 *
+	 * Also, board-specific knowledge may allow us to use the 
+	 * CACHE Flash_Invalidate_T instruction if the tag RAM supports
+	 * it, and may specify the size of the L3 cache so we don't have
+	 * to probe it. 
+	 */
+	printk(KERN_INFO "Tertiary cache present, %s enabled\n",
+	       config&(1<<12) ? "already" : "not (yet)");
+
+	if ((config >> 12) & 1)
+		rm7k_tcache_enabled = 1;
+}
+
+void __init ld_mmu_rm7k(void)
+{
+	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
+	unsigned long addr;
+
+	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
+
+        change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+
+	/* RM7000 erratum #31. The icache is screwed at startup. */
+	set_taglo(0);
+	set_taghi(0);
+	for (addr = KSEG0; addr <= KSEG0 + 4096; addr += ic_lsize) {
+		__asm__ __volatile__ (
+			".set noreorder\n\t"
+			".set mips3\n\t"
+			"cache\t%1, 0(%0)\n\t"
+			"cache\t%1, 0x1000(%0)\n\t"
+			"cache\t%1, 0x2000(%0)\n\t"
+			"cache\t%1, 0x3000(%0)\n\t"
+			"cache\t%2, 0(%0)\n\t"
+			"cache\t%2, 0x1000(%0)\n\t"
+			"cache\t%2, 0x2000(%0)\n\t"
+			"cache\t%2, 0x3000(%0)\n\t"
+			"cache\t%1, 0(%0)\n\t"
+			"cache\t%1, 0x1000(%0)\n\t"
+			"cache\t%1, 0x2000(%0)\n\t"
+			"cache\t%1, 0x3000(%0)\n\t"
+			".set\tmips0\n\t"
+			".set\treorder\n\t"
+			:
+			: "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill));
+	}
+
+#ifndef CONFIG_MIPS_UNCACHED
+	change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+#endif
+
+	probe_icache(config);
+	probe_dcache(config);
+	probe_scache(config);
+	probe_tcache(config);
+
+	printk("TLB has %d entries.\n", ntlb_entries());
+
+	_clear_page = rm7k_clear_page;
+	_copy_page = rm7k_copy_page;
+
+	_flush_cache_all = rm7k_flush_cache_all_d32i32;
+	___flush_cache_all = __flush_cache_all_d32i32;
+	_flush_cache_mm = rm7k_flush_cache_mm_d32i32;
+	_flush_cache_range = rm7k_flush_cache_range_d32i32;
+	_flush_cache_page = rm7k_flush_cache_page_d32i32;
+	_flush_page_to_ram = rm7k_flush_page_to_ram_d32i32;
+	_flush_cache_sigtramp = rm7k_flush_cache_sigtramp;
+	_flush_icache_range = rm7k_flush_icache_range;
+	_flush_icache_page = rm7k_flush_icache_page;
+
+	_dma_cache_wback_inv = rm7k_dma_cache_wback_inv;
+	_dma_cache_wback = rm7k_dma_cache_wback;
+	_dma_cache_inv = rm7k_dma_cache_inv;
+
+	__flush_cache_all_d32i32();
+	write_32bit_cp0_register(CP0_WIRED, 0);
+	temp_tlb_entry = ntlb_entries() - 1;
+	write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
+	flush_tlb_all();
+}
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/sb1.c linux/arch/mips/mm/sb1.c
--- v2.4.6/linux/arch/mips/mm/sb1.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mm/sb1.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 2000 Sibyte
+ * 
+ * Written by Justin Carlson (carlson@sibyte.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */ 
+
+
+/*
+ * In this entire file, I'm not sure what the role of the L2 on the sb1250 
+ * is.  Since it is coherent to the system, we should never need to flush
+ * it...right?...right???  -JDC
+ */
+
+#include <asm/mmu_context.h>
+
+/* These are probed at ld_mmu time */
+static unsigned int icache_size;
+static unsigned int dcache_size;
+
+static unsigned int icache_line_size;
+static unsigned int dcache_line_size;
+
+static unsigned int icache_assoc;
+static unsigned int dcache_assoc;
+
+static unsigned int icache_sets;
+static unsigned int dcache_sets;
+static unsigned int tlb_entries;
+
+void pgd_init(unsigned long page)
+{
+	unsigned long *p = (unsigned long *) page;
+	int i;
+
+	for (i = 0; i < USER_PTRS_PER_PGD; i+=8) {
+		p[i + 0] = (unsigned long) invalid_pte_table;
+		p[i + 1] = (unsigned long) invalid_pte_table;
+		p[i + 2] = (unsigned long) invalid_pte_table;
+		p[i + 3] = (unsigned long) invalid_pte_table;
+		p[i + 4] = (unsigned long) invalid_pte_table;
+		p[i + 5] = (unsigned long) invalid_pte_table;
+		p[i + 6] = (unsigned long) invalid_pte_table;
+		p[i + 7] = (unsigned long) invalid_pte_table;
+	}
+}
+
+void flush_tlb_all(void)
+{
+	unsigned long flags;
+	unsigned long old_ctx;
+	int entry;
+
+	__save_and_cli(flags);
+	/* Save old context and create impossible VPN2 value */
+	old_ctx = (get_entryhi() & 0xff);
+	set_entrylo0(0);
+	set_entrylo1(0);
+	for (entry = 0; entry < tlb_entries; entry++) {
+		set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry);
+		set_index(entry);
+		tlb_write_indexed();
+	}
+	set_entryhi(old_ctx);
+	__restore_flags(flags);	
+}
+
+
+
+/* These are the functions hooked by the memory management function pointers */
+static void sb1_clear_page(void *page)
+{
+	/* JDCXXX - This should be bottlenecked by the write buffer, but these
+	   things tend to be mildly unpredictable...should check this on the
+	   performance model */
+
+	/* We prefetch 4 lines ahead.  We're also "cheating" slightly here...
+	   since we know we're on an SB1, we force the assembler to take 
+	   64-bit operands to speed things up */
+	__asm__ __volatile__(
+		".set push                  \n"
+		".set noreorder             \n"
+		".set noat                  \n"
+		".set mips4                 \n"
+		"     addiu     $1, %0, %2  \n"  /* Calculate the end of the page to clear */
+		"     pref       5,  0(%0)  \n"  /* Prefetch the first 4 lines */
+		"     pref       5, 32(%0)  \n"  
+		"     pref       5, 64(%0)  \n"  
+		"     pref       5, 96(%0)  \n"  
+		"1:   sd        $0,  0(%0)  \n"  /* Throw out a cacheline of 0's */
+		"     sd        $0,  8(%0)  \n"
+		"     sd        $0, 16(%0)  \n"
+		"     sd        $0, 24(%0)  \n"
+		"     pref       5,128(%0)  \n"  /* Prefetch 4 lines ahead     */
+		"     bne       $1, %0, 1b  \n"
+		"     addiu     %0, %0, 32  \n"  /* Next cacheline (This instruction better be short piped!) */
+		".set pop                   \n"
+		:"=r" (page)
+		:"0" (page),
+		 "I" (PAGE_SIZE-32)
+		:"$1","memory");
+
+}
+
+static void sb1_copy_page(void *to, void *from)
+{
+
+	/* This should be optimized in assembly...can't use ld/sd, though,
+	 * because the top 32 bits could be nuked if we took an interrupt
+	 * during the routine.  And this is not a good place to be cli()'ing
+	 */
+
+	/* The pref's used here are using "streaming" hints, which cause the
+	 * copied data to be kicked out of the cache sooner.  A page copy often
+	 * ends up copying a lot more data than is commonly used, so this seems
+	 * to make sense in terms of reducing cache pollution, but I've no real
+	 * performance data to back this up
+	 */ 
+
+	__asm__ __volatile__(
+		".set push                  \n"
+		".set noreorder             \n"
+		".set noat                  \n"
+		".set mips4                 \n"
+		"     addiu     $1, %0, %4  \n"  /* Calculate the end of the page to copy */
+		"     pref       4,  0(%0)  \n"  /* Prefetch the first 3 lines to be read and copied */
+		"     pref       5,  0(%1)  \n"  
+		"     pref       4, 32(%0)  \n"  
+		"     pref       5, 32(%1)  \n"  
+		"     pref       4, 64(%0)  \n"  
+		"     pref       5, 64(%1)  \n"  
+		"1:   lw        $2,  0(%0)  \n"  /* Block copy a cacheline */
+		"     lw        $3,  4(%0)  \n"
+		"     lw        $4,  8(%0)  \n"
+		"     lw        $5, 12(%0)  \n"
+		"     lw        $6, 16(%0)  \n"
+		"     lw        $7, 20(%0)  \n"
+		"     lw        $8, 24(%0)  \n"
+		"     lw        $9, 28(%0)  \n"
+		"     pref       4, 96(%0)  \n"  /* Prefetch ahead         */
+		"     pref       5, 96(%1)  \n"
+		"     sw        $2,  0(%1)  \n"  
+		"     sw        $3,  4(%1)  \n"
+		"     sw        $4,  8(%1)  \n"
+		"     sw        $5, 12(%1)  \n"
+		"     sw        $6, 16(%1)  \n"
+		"     sw        $7, 20(%1)  \n"
+		"     sw        $8, 24(%1)  \n"
+		"     sw        $9, 28(%1)  \n"		
+		"     addiu     %1, %1, 32  \n"  /* Next cacheline */
+		"     nop                   \n"  /* Force next add to short pipe */
+		"     nop                   \n"  /* Force next add to short pipe */
+		"     bne       $1, %0, 1b  \n"
+		"     addiu     %0, %0, 32  \n"  /* Next cacheline */
+		".set pop                   \n" 
+		:"=r" (to),
+		"=r" (from)
+		:
+		"0" (from),
+		"1" (to),
+		"I" (PAGE_SIZE-32)
+		:"$1","$2","$3","$4","$5","$6","$7","$8","$9","memory");
+/*
+	unsigned long *src = from;
+	unsigned long *dest = to;
+	unsigned long *target = (unsigned long *) (((unsigned long)src) + PAGE_SIZE);
+	while (src != target) {
+		*dest++ = *src++;
+	}
+*/
+}
+
+/*
+ * The dcache is fully coherent to the system, with one
+ * big caveat:  the instruction stream.  In other words,
+ * if we miss in the icache, and have dirty data in the
+ * L1 dcache, then we'll go out to memory (or the L2) and
+ * get the not-as-recent data.
+ * 
+ * So the only time we have to flush the dcache is when
+ * we're flushing the icache.  Since the L2 is fully
+ * coherent to everything, including I/O, we never have
+ * to flush it
+ */
+
+static void sb1_flush_cache_all(void)
+{
+
+	/*
+	 * Haven't worried too much about speed here; given that we're flushing
+	 * the icache, the time to invalidate is dwarfed by the time it's going
+	 * to take to refill it.  Register usage:
+	 * 
+	 * $1 - moving cache index
+	 * $2 - set count
+	 */
+	if (icache_sets) { 
+		__asm__ __volatile__ (
+			".set push                  \n"
+			".set noreorder             \n"
+			".set noat                  \n"
+			".set mips4                 \n"
+			"     move   $1, %2         \n" /* Start at index 0 */
+                        "1:   cache  0, 0($1)       \n" /* Invalidate this index */
+			"     addiu  %1, %1, -1     \n" /* Decrement loop count */
+			"     bnez   %1, 1b         \n" /* loop test */
+			"     addu   $1, $1, %0     \n" /* Next address JDCXXX - Should be short piped */
+			".set pop                   \n"
+			::"r" (icache_line_size),
+			"r" (icache_sets * icache_assoc),
+			"r" (KSEG0)
+			:"$1");
+	}
+	if (dcache_sets) {
+		__asm__ __volatile__ (
+			".set push                  \n"
+			".set noreorder             \n"
+			".set noat                  \n"
+			".set mips4                 \n"
+			"     move   $1, %2         \n" /* Start at index 0 */
+                        "1:   cache  0x1, 0($1)     \n" /* WB/Invalidate this index */
+			"     addiu  %1, %1, -1     \n" /* Decrement loop count */
+			"     bnez   %1, 1b         \n" /* loop test */
+			"     addu   $1, $1, %0     \n" /* Next address JDCXXX - Should be short piped */
+			".set pop                   \n"
+			::"r" (dcache_line_size),
+			"r" (dcache_sets * dcache_assoc),
+			"r" (KSEG0)
+			:"$1");
+	}
+}
+
+/*
+ * When flushing a range in the icache, we have to first writeback
+ * the dcache for the same range, so new ifetches will see any
+ * data that was dirty in the dcache
+ */
+
+static void sb1_flush_icache_range(unsigned long start, unsigned long end)
+{
+	
+	/* JDCXXX - Implement me! */
+	sb1_flush_cache_all();
+}
+
+static void sb1_flush_cache_mm(struct mm_struct *mm)
+{
+	/* Don't need to do this, as the dcache is physically tagged */
+}
+
+static void sb1_flush_cache_range(struct mm_struct *mm, 
+				  unsigned long start,
+				  unsigned long end)
+{
+	/* Don't need to do this, as the dcache is physically tagged */
+}
+
+
+static void sb1_flush_cache_sigtramp(unsigned long page)
+{
+	/* JDCXXX - Implement me! */
+	sb1_flush_cache_all();
+}
+
+
+/*
+ * This only needs to make sure stores done up to this
+ * point are visible to other agents outside the CPU.  Given 
+ * the coherent nature of the ZBus, all that's required here is 
+ * a sync to make sure the data gets out to the caches and is
+ * visible to an arbitrary A Phase from an external agent 
+ *   
+ * Actually, I'm not even sure that's necessary; the semantics
+ * of this function aren't clear.  If it's supposed to serve as
+ * a memory barrier, this is needed.  If it's only meant to 
+ * prevent data from being invisible to non-cpu memory accessors
+ * for some indefinite period of time (e.g. in a non-coherent 
+ * dcache) then this function would be a complete nop.
+ */
+static void sb1_flush_page_to_ram(struct page *page)
+{
+	__asm__ __volatile__(
+		"     sync  \n"  /* Short pipe */
+		:::"memory");	
+}
+
+
+/* Cribbed from the r2300 code */
+static void sb1_flush_cache_page(struct vm_area_struct *vma,
+				  unsigned long page)
+{
+	sb1_flush_cache_all();
+#if 0
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long physpage;
+
+	/* No icache flush needed without context; */
+	if (mm->context == 0) 
+		return;  
+
+	/* No icache flush needed if the page isn't executable */
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
+
+	physpage = (unsigned long) page_address(page);
+	if (physpage)
+		sb1_flush_icache_range(physpage, physpage + PAGE_SIZE);
+#endif
+}
+
+
+/*
+ *  Cache set values (from the mips64 spec)
+ * 0 - 64
+ * 1 - 128
+ * 2 - 256
+ * 3 - 512
+ * 4 - 1024
+ * 5 - 2048
+ * 6 - 4096
+ * 7 - Reserved
+ */
+static unsigned int decode_cache_sets(unsigned int config_field)
+{
+	if (config_field == 7) {
+		/* JDCXXX - Find a graceful way to abort. */
+		return 0;
+	} 
+
+	return (1<<(config_field + 6));
+}
+
+/*
+ *  Cache line size values (from the mips64 spec)
+ * 0 - No cache present.
+ * 1 - 4 bytes
+ * 2 - 8 bytes
+ * 3 - 16 bytes
+ * 4 - 32 bytes
+ * 5 - 64 bytes
+ * 6 - 128 bytes
+ * 7 - Reserved
+ */
+static unsigned int decode_cache_line_size(unsigned int config_field)
+{
+	if (config_field == 0) {
+		return 0;
+	} else if (config_field == 7) {
+		/* JDCXXX - Find a graceful way to abort. */
+		return 0;
+	} 
+	return (1<<(config_field + 1));
+}
+
+/*
+ * Relevant bits of the config1 register format (from the MIPS32/MIPS64 specs)
+ *
+ * 24:22 Icache sets per way
+ * 21:19 Icache line size
+ * 18:16 Icache Associativity
+ * 15:13 Dcache sets per way
+ * 12:10 Dcache line size
+ * 9:7   Dcache Associativity
+ */
+
+
+static void probe_cache_sizes(void)
+{
+	u32 config1;
+
+	__asm__ __volatile__(
+		".set push                  \n"
+		".set mips64                \n"
+		"     mfc0    %0, $16, 1    \n"  /* Get config1 register */
+		".set pop                   \n"
+		:"=r" (config1));
+	icache_line_size = decode_cache_line_size((config1 >> 19) & 0x7);
+	dcache_line_size = decode_cache_line_size((config1 >> 10) & 0x7);
+	icache_sets = decode_cache_sets((config1 >> 22) & 0x7);
+	dcache_sets = decode_cache_sets((config1 >> 13) & 0x7);
+        icache_assoc = ((config1 >> 16) & 0x7) + 1;
+	dcache_assoc = ((config1 >> 7) & 0x7) + 1;
+	icache_size = icache_line_size * icache_sets * icache_assoc;
+	dcache_size = dcache_line_size * dcache_sets * dcache_assoc;
+	tlb_entries = ((config1 >> 25) & 0x3f) + 1;
+}
+
+
+/* This is called from loadmmu.c.  We have to set up all the
+   memory management function pointers, as well as initialize
+   the caches and tlbs */
+void ld_mmu_sb1(void)
+{
+	probe_cache_sizes();
+
+	_clear_page = sb1_clear_page;
+	_copy_page = sb1_copy_page;
+	
+	_flush_cache_all = sb1_flush_cache_all;
+	_flush_cache_mm = sb1_flush_cache_mm;
+	_flush_cache_range = sb1_flush_cache_range;
+	_flush_cache_page = sb1_flush_cache_page;
+	_flush_cache_sigtramp = sb1_flush_cache_sigtramp;
+
+	_flush_page_to_ram = sb1_flush_page_to_ram;
+	_flush_icache_page = sb1_flush_cache_page;
+	_flush_icache_range = sb1_flush_icache_range;
+
+	
+	/*
+	 * JDCXXX I'm not sure whether these are necessary: is this the right 
+	 * place to initialize the tlb?  If it is, why is it done 
+	 * at this level instead of as common code in loadmmu()?
+	 */
+	flush_cache_all();
+	flush_tlb_all();
+	
+	/* Turn on caching in kseg0 */
+	set_cp0_config(CONF_CM_CMASK, 0);
+}
diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c
--- v2.4.6/linux/arch/mips/mm/umap.c	Mon Mar 19 12:35:09 2001
+++ linux/arch/mips/mm/umap.c	Wed Jul  4 11:50:39 2001
@@ -1,6 +1,4 @@
 /*
- * arch/mips/mm/umap.c
- *
  * (C) Copyright 1994 Linus Torvalds
  *
  * Changes:
@@ -21,6 +19,7 @@
 #include <linux/shm.h>
 #include <linux/errno.h>
 #include <linux/mman.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
@@ -106,6 +105,8 @@
 	up_write (&task->mm->mmap_sem);
 }
 
+EXPORT_SYMBOL(remove_mapping);
+
 void *vmalloc_uncached (unsigned long size)
 {
 	return __vmalloc (size, GFP_KERNEL | __GFP_HIGHMEM,
@@ -180,7 +181,7 @@
 		end = PGDIR_SIZE;
 	vaddr -= address;
 	do {
-		pte_t * pte = pte_alloc(pmd, address);
+		pte_t * pte = pte_alloc(current->mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		vmap_pte_range(pte, address, end - address, address + vaddr);
@@ -202,7 +203,7 @@
 	dir = pgd_offset(current->mm, from);
 	flush_cache_range(current->mm, beg, end);
 	while (from < end) {
-		pmd_t *pmd = pmd_alloc(dir, from);
+		pmd_t *pmd = pmd_alloc(current->mm, dir, from);
 		error = -ENOMEM;
 		if (!pmd)
 			break;
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/Makefile linux/arch/mips64/Makefile
--- v2.4.6/linux/arch/mips64/Makefile	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/Makefile	Wed Jul  4 11:50:38 2001
@@ -64,6 +64,11 @@
 CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips4
 endif
 
+ifdef CONFIG_MIPS_FPU_EMULATOR
+CORE_FILES	+= arch/mips64/math-emu/fpu_emulator.o
+SUBDIRS		+= arch/mips64/math-emu
+endif
+
 #
 # Board-dependent options and extra files
 #
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/Makefile linux/arch/mips64/arc/Makefile
--- v2.4.6/linux/arch/mips64/arc/Makefile	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/arc/Makefile	Wed Jul  4 11:50:39 2001
@@ -3,13 +3,10 @@
 #
 
 L_TARGET = arclib.a
-obj-y	:= init.o printf.o tree.o env.o cmdline.o misc.o time.o file.o \
-	   identify.o
-
-ifndef CONFIG_SGI_IP27
-  obj-y += console.o
-endif
+obj-y	:= console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \
+	   file.o
 
 obj-$(CONFIG_ARC_MEMORY) += memory.o
+obj-$(CONFIG_ARC_CONSOLE) += arc_con.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/arc_con.c linux/arch/mips64/arc/arc_con.c
--- v2.4.6/linux/arch/mips64/arc/arc_con.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips64/arc/arc_con.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,78 @@
+/*
+ * Wrap-around code for a console using the
+ * ARC io-routines.
+ *
+ * Copyright (c) 1998 Harald Koerfgen 
+ * Copyright (c) 2001 Ralf Baechle
+ */
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+
+#include <asm/sgialib.h>
+
+extern void prom_printf (char *, ...);
+
+void prom_putchar(char c)
+{
+	ULONG cnt;
+	CHAR it = c;
+
+	ArcWrite(1, &it, 1, &cnt);
+}
+
+static void prom_console_write(struct console *co, const char *s,
+			       unsigned count)
+{
+	unsigned i;
+
+	/*
+	 *    Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		if (*s == 10)
+			prom_printf("%c", 13);
+		prom_printf("%c", *s++);
+	}
+}
+
+static int prom_console_wait_key(struct console *co)
+{
+	return 0;
+}
+
+static int __init prom_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+static kdev_t prom_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console arc_cons = {
+	"ttyS",
+	prom_console_write,
+	NULL,
+	prom_console_device,
+	prom_console_wait_key,
+	NULL,
+	prom_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *    Register console.
+ */
+
+void __init arc_console_init(void)
+{
+	register_console(&arc_cons);
+}
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/cmdline.c linux/arch/mips64/arc/cmdline.c
--- v2.4.6/linux/arch/mips64/arc/cmdline.c	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/arc/cmdline.c	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: cmdline.c,v 1.2 1999/10/19 20:51:44 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -30,10 +29,49 @@
 	"SystemPartition=",
 	"OSLoader=",
 	"OSLoadPartition=",
-	"OSLoadFilename="
+	"OSLoadFilename=",
+	"OSLoadOptions="
 };
 #define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0])))))
 
+static char *used_arc[][2] = {
+	{ "OSLoadPartition=", "root=" },
+	{ "OSLoadOptions=", "" }
+};
+
+static char * __init move_firmware_args(char* cp)
+{
+	char *s;
+	int actr, i;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	while (actr < prom_argc) {
+		for(i = 0; i < NENTS(used_arc); i++) {
+			int len = strlen(used_arc[i][0]);
+
+			if (!strncmp(prom_argv(actr), used_arc[i][0], len)) {
+			/* Ok, we want it. First append the replacement... */
+				strcat(cp, used_arc[i][1]);
+				cp += strlen(used_arc[i][1]);
+				/* ... and now the argument */
+				s = strstr(prom_argv(actr), "=");
+				if (s) {
+					s++;
+					strcpy(cp, s);
+					cp += strlen(s);
+				}
+				*cp++ = ' ';
+				break;
+			}
+		}
+		actr++;
+	}
+
+	return cp;
+}
+
+
 void __init prom_init_cmdline(void)
 {
 	char *cp;
@@ -42,11 +80,17 @@
 	actr = 1; /* Always ignore argv[0] */
 
 	cp = &(arcs_cmdline[0]);
-	while(actr < prom_argc) {
-		for(i = 0; i < NENTS(ignored); i++) {
+	/* 
+	 * Move ARC variables to the beginning to make sure they can be
+	 * overridden by later arguments.
+	 */
+	cp = move_firmware_args(cp);
+
+	while (actr < prom_argc) {
+		for (i = 0; i < NENTS(ignored); i++) {
 			int len = strlen(ignored[i]);
 
-			if(!strncmp(prom_argv(actr), ignored[i], len))
+			if (!strncmp(prom_argv(actr), ignored[i], len))
 				goto pic_cont;
 		}
 		/* Ok, we want it. */
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/console.c linux/arch/mips64/arc/console.c
--- v2.4.6/linux/arch/mips64/arc/console.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/arc/console.c	Wed Jul  4 11:50:39 2001
@@ -6,22 +6,28 @@
  * Copyright (C) 1996 David S. Miller (dm@sgi.com)
  */
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <asm/sgialib.h>
 
-void prom_putchar(char c)
+static char ppbuf[1024];
+
+void prom_printf(char *fmt, ...)
 {
-	ULONG cnt;
-	CHAR it = c;
+	va_list args;
+	char ch, *bptr;
+	int i;
 
-	ArcWrite(1, &it, 1, &cnt);
-}
+	va_start(args, fmt);
+	i = vsprintf(ppbuf, fmt, args);
 
-char __init prom_getchar(void)
-{
-	ULONG cnt;
-	CHAR c;
+	bptr = ppbuf;
 
-	ArcRead(0, &c, 1, &cnt);
+	while((ch = *(bptr++)) != 0) {
+		if(ch == '\n')
+			prom_putchar('\r');
 
-	return c;
+		prom_putchar(ch);
+	}
+	va_end(args);
+	return;
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/identify.c linux/arch/mips64/arc/identify.c
--- v2.4.6/linux/arch/mips64/arc/identify.c	Sun Jul  9 22:18:15 2000
+++ linux/arch/mips64/arc/identify.c	Wed Jul  4 11:50:39 2001
@@ -42,14 +42,11 @@
 {
 	int i;
     
-	for (i = 0; i < sizeof (mach_table); i++) {
+	for (i = 0; i < (sizeof (mach_table) / sizeof (mach_table[0])); i++) {
 		if(!strcmp(s, mach_table[i].name))
 			return &mach_table[i];
 	}
-	prom_printf("\nYeee, could not determine architecture type <%s>\n", s);
-	prom_printf("press a key to reboot\n");
-	prom_getchar();
-	ArcEnterInteractiveMode();
+	panic("\nYeee, could not determine architecture type <%s>", s);
 
 	return NULL;
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/memory.c linux/arch/mips64/arc/memory.c
--- v2.4.6/linux/arch/mips64/arc/memory.c	Mon Aug  7 21:02:27 2000
+++ linux/arch/mips64/arc/memory.c	Wed Jul  4 11:50:39 2001
@@ -1,11 +1,9 @@
-/* $Id: memory.c,v 1.5 2000/01/27 23:21:57 ralf Exp $
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
+/*
+ * memory.c: PROM library functions for acquiring/using memory descriptors
+ *           given to us from the ARCS firmware.
  *
  * Copyright (C) 1996 by David S. Miller
- * Copyright (C) 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 by Ralf Baechle
  * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
  *
  * PROM library functions for acquiring/using memory descriptors given to us
@@ -41,7 +39,7 @@
 	"Free/Contig RAM",
 	"Generic Free RAM",
 	"Bad Memory",
-	"Standlong Program Pages",
+	"Standalone Program Pages",
 	"ARCS Temp Storage Area",
 	"ARCS Permanent Storage Area"
 };
@@ -54,31 +52,25 @@
 	"LoadedProgram",
 	"FirmwareTemporary",
 	"FirmwarePermanent",
-	"FreeContigiuous"
+	"FreeContiguous"
 };
 #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc]
 #endif
 
-static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS];
-
-#define MEMTYPE_DONTUSE   0
-#define MEMTYPE_PROM      1
-#define MEMTYPE_FREE      2
-
 static inline int memtype_classify_arcs (union linux_memtypes type)
 {
 	switch (type.arcs) {
 	case arcs_fcontig:
 	case arcs_free:
-		return MEMTYPE_FREE;
+		return BOOT_MEM_RAM;
 	case arcs_atmp:
-		return MEMTYPE_PROM;
+		return BOOT_MEM_ROM_DATA;
 	case arcs_eblock:
 	case arcs_rvpage:
 	case arcs_bmem:
 	case arcs_prog:
 	case arcs_aperm:
-		return MEMTYPE_DONTUSE;
+		return BOOT_MEM_RESERVED;
 	default:
 		BUG();
 	}
@@ -90,15 +82,15 @@
 	switch (type.arc) {
 	case arc_free:
 	case arc_fcontig:
-		return MEMTYPE_FREE;
+		return BOOT_MEM_RAM;
 	case arc_atmp:
-		return MEMTYPE_PROM;
+		return BOOT_MEM_ROM_DATA;
 	case arc_eblock:
 	case arc_rvpage:
 	case arc_bmem:
 	case arc_prog:
 	case arc_aperm:
-		return MEMTYPE_DONTUSE;
+		return BOOT_MEM_RESERVED;
 	default:
 		BUG();
 	}
@@ -113,52 +105,18 @@
 	return memtype_classify_arc(type);
 }
 
-static inline unsigned long find_max_low_pfn(void)
-{
-	struct prom_pmemblock *p, *highest;
-	unsigned long pfn;
-
-	p = pblocks;
-	highest = 0;
-	while (p->size != 0) {
-		if (!highest || p->base > highest->base)
-			highest = p;
-		p++;
-	}
-
-	pfn = (highest->base + highest->size) >> PAGE_SHIFT;
-#ifdef DEBUG
-	prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn);
-#endif
-	return pfn;
-}
-
-static inline struct prom_pmemblock *find_largest_memblock(void)
-{
-	struct prom_pmemblock *p, *largest;
-
-	p = pblocks;
-	largest = 0;
-	while (p->size != 0) {
-		if (!largest || p->size > largest->size)
-			largest = p;
-		p++;
-	}
-
-	return largest;
-}
-
 void __init prom_meminit(void)
 {
-	struct prom_pmemblock *largest;
-	unsigned long bootmap_size;
 	struct linux_mdesc *p;
-	int totram;
-	int i = 0;
 
 #ifdef DEBUG
+	int i = 0;
+
 	prom_printf("ARCS MEMORY DESCRIPTOR dump:\n");
+	i=0;
+	prom_printf ("i=%d\n", i);
 	p = ArcGetMemoryDescriptor(PROM_NULL_MDESC);
+	prom_printf ("i=%d\n", i);
 	while(p) {
 		prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n",
 			    i, p, p->base, p->pages, mtypes(p->type));
@@ -167,56 +125,17 @@
 	}
 #endif
 
-	totram = 0;
-	i = 0;
 	p = PROM_NULL_MDESC;
 	while ((p = ArcGetMemoryDescriptor(p))) {
-		pblocks[i].type = prom_memtype_classify(p->type);
-		pblocks[i].base = p->base << PAGE_SHIFT;
-		pblocks[i].size = p->pages << PAGE_SHIFT;
-
-		switch (pblocks[i].type) {
-		case MEMTYPE_FREE:
-			totram += pblocks[i].size;
-#ifdef DEBUG
-			prom_printf("free_chunk[%d]: base=%08lx size=%x\n",
-				    i, pblocks[i].base,
-				    pblocks[i].size);
-#endif
-			i++;
-			break;
-		case MEMTYPE_PROM:
-#ifdef DEBUG
-			prom_printf("prom_chunk[%d]: base=%08lx size=%x\n",
-				    i, pblocks[i].base,
-				    pblocks[i].size);
-#endif
-			i++;
-			break;
-		default:
-			break;
-		}
-	}
-	pblocks[i].size = 0;
+		unsigned long base, size;
+		long type;
 
-	max_low_pfn = find_max_low_pfn();
-	largest = find_largest_memblock();
-	bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn);
-
-	for (i = 0; pblocks[i].size; i++)
-		if (pblocks[i].type == MEMTYPE_FREE)
-			free_bootmem(pblocks[i].base, pblocks[i].size);
-
-	/* This test is simpleminded.  It will fail if the bootmem bitmap
-	   falls into multiple adjacent ARC memory areas.  */
-	if (bootmap_size > largest->size) {
-		prom_printf("CRITIAL: overwriting PROM data.\n");
-		BUG();
-	}
-	reserve_bootmem(largest->base, bootmap_size);
+		base = p->base << PAGE_SHIFT;
+		size = p->pages << PAGE_SHIFT;
+		type = prom_memtype_classify(p->type);
 
-	printk("PROMLIB: Total free ram %dK / %dMB.\n",
-	       totram >> 10, totram >> 20);
+		add_memory_region(base, size, type);
+	}
 }
 
 void __init
@@ -224,18 +143,19 @@
 {
 	struct prom_pmemblock *p;
 	unsigned long freed = 0;
-	unsigned long addr, end;
+	unsigned long addr;
+	int i;
 
-	for (p = pblocks; p->size != 0; p++) {
-		if (p->type != MEMTYPE_PROM)
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
 			continue;
 
-		addr = PAGE_OFFSET + (unsigned long) (long) p->base;
-		end = addr + (unsigned long) (long) p->size;
-		while (addr < end) {
-			ClearPageReserved(virt_to_page(addr));
-			set_page_count(virt_to_page(addr), 1);
-			free_page(addr);
+		addr = boot_mem_map.map[i].addr;
+		while (addr < boot_mem_map.map[i].addr
+			      + boot_mem_map.map[i].size) {
+			ClearPageReserved(virt_to_page(__va(addr)));
+			set_page_count(virt_to_page(__va(addr)), 1);
+			free_page((unsigned long)__va(addr));
 			addr += PAGE_SIZE;
 			freed += PAGE_SIZE;
 		}
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/printf.c linux/arch/mips64/arc/printf.c
--- v2.4.6/linux/arch/mips64/arc/printf.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/arc/printf.c	Wed Dec 31 16:00:00 1969
@@ -1,37 +0,0 @@
-/* $Id: printf.c,v 1.1 1999/08/20 21:13:33 ralf Exp $
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Putting things on the screen using SGI arcs PROM facilities.
- *
- * Copyright (C) 1996 David S. Miller (dm@sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/sgialib.h>
-
-static char ppbuf[1024];
-
-void prom_printf(char *fmt, ...)
-{
-	va_list args;
-	char ch, *bptr;
-	int i;
-
-	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
-	va_end(args);
-	return;
-}
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/tree.c linux/arch/mips64/arc/tree.c
--- v2.4.6/linux/arch/mips64/arc/tree.c	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/arc/tree.c	Wed Jul  4 11:50:39 2001
@@ -123,8 +123,6 @@
 		dump_component(p);
 		p = ArcGetPeer(p);
 	}
-	prom_printf("press a key\n");
-	prom_getchar();
 }
 
 #endif /* DEBUG_PROM_TREE  */
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/config.in linux/arch/mips64/config.in
--- v2.4.6/linux/arch/mips64/config.in	Tue Apr 17 17:19:25 2001
+++ linux/arch/mips64/config.in	Wed Jul  4 11:50:39 2001
@@ -11,8 +11,10 @@
 
 mainmenu_option next_comment
 comment 'Machine selection'
-bool 'Support for SGI IP22' CONFIG_SGI_IP22
-bool 'Support for SGI IP27' CONFIG_SGI_IP27
+choice 'Machine type'						\
+	"SGI-IP22,Indy/Indigo2 CONFIG_SGI_IP22			\
+	 SGI-IP27,Origin200/2000 CONFIG_SGI_IP27 SGI-IP27,Origin200/2000"
+
 if [ "$CONFIG_SGI_IP27" = "y" ]; then
    bool '  IP27 N-Mode' CONFIG_SGI_SN0_N_MODE
    bool '  Discontiguous Memory Support' CONFIG_DISCONTIGMEM
@@ -47,6 +49,7 @@
    define_bool CONFIG_BOARD_SCACHE y
    define_bool CONFIG_ARC_MEMORY y
    define_bool CONFIG_SGI y
+   define_int CONFIG_L1_CACHE_SHIFT 5
 fi
 
 if [ "$CONFIG_SGI_IP27" = "y" ]; then
@@ -55,6 +58,7 @@
    define_bool CONFIG_COHERENT_IO y
    define_bool CONFIG_PCI y
    define_bool CONFIG_QL_ISP_A64 y
+   define_int CONFIG_L1_CACHE_SHIFT 7
 fi
 
 if [ "$CONFIG_ISA" != "y" ]; then
@@ -91,6 +95,10 @@
 fi
 bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool 'Kernel floating-point emulation' CONFIG_MIPS_FPU_EMULATOR
+fi
+
 bool 'Networking support' CONFIG_NET
 
 source drivers/pci/Config.in
@@ -106,6 +114,11 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
+
+if [ "$CONFIG_ARC32" = "y" ]; then
+   bool 'ARC console support' CONFIG_ARC_CONSOLE
+fi
+
 tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
 bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT
 if [ "$CONFIG_MIPS32_COMPAT" = "y" ]; then
@@ -125,14 +138,12 @@
 
 source drivers/pci/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
-fi
-
 endmenu
 
 source drivers/mtd/Config.in
 
+source drivers/parport/Config.in
+
 source drivers/block/Config.in
 
 source drivers/md/Config.in
@@ -166,7 +177,7 @@
 fi
 endmenu
 
-source drivers/i2o/Config.in
+source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
    mainmenu_option next_comment
@@ -175,16 +186,6 @@
    bool 'Network device support' CONFIG_NETDEVICES
    if [ "$CONFIG_NETDEVICES" = "y" ]; then
       source drivers/net/Config.in
-      if [ "$CONFIG_SGI_IP22" = "y" ]; then
-	 bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ
-      fi
-      if [ "$CONFIG_DECSTATION" = "y" ]; then
-	 bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE
-      fi
-      if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
-	 tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE
-	 tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM
-      fi
       if [ "$CONFIG_ATM" = "y" ]; then
 	 source drivers/atm/Config.in
       fi
@@ -227,6 +228,7 @@
 if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
    comment 'Console drivers'
+   source drivers/video/Config.in
    if [ "$CONFIG_SGI_IP22" = "y" ]; then
       tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
       if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then
@@ -268,4 +270,7 @@
 fi
 bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+if [ "$CONFIG_SMP" != "n" ]; then
+   bool 'Run uncached' CONFIG_MIPS_UNCACHED
+fi
 endmenu
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/defconfig linux/arch/mips64/defconfig
--- v2.4.6/linux/arch/mips64/defconfig	Fri Apr 13 20:26:07 2001
+++ linux/arch/mips64/defconfig	Wed Jul  4 11:50:39 2001
@@ -14,16 +14,19 @@
 CONFIG_SGI_IP27=y
 # CONFIG_SGI_SN0_N_MODE is not set
 CONFIG_DISCONTIGMEM=y
-# CONFIG_NUMA is not set
+CONFIG_NUMA=y
 # CONFIG_MAPPED_KERNEL is not set
 # CONFIG_REPLICATE_KTEXT is not set
 # CONFIG_REPLICATE_EXHANDLERS is not set
 CONFIG_SMP=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF64=y
 CONFIG_ARC64=y
 CONFIG_COHERENT_IO=y
 CONFIG_PCI=y
 CONFIG_QL_ISP_A64=y
+CONFIG_L1_CACHE_SHIFT=7
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
@@ -68,6 +71,11 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
@@ -95,19 +103,24 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 
@@ -187,8 +200,6 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
@@ -254,7 +265,6 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -302,9 +312,8 @@
 CONFIG_SERIAL_CONSOLE=y
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 
 #
 # I2C support
@@ -370,10 +379,12 @@
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
@@ -381,7 +392,7 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
@@ -458,3 +469,4 @@
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22
--- v2.4.6/linux/arch/mips64/defconfig-ip22	Fri Apr 13 20:26:07 2001
+++ linux/arch/mips64/defconfig-ip22	Wed Jul  4 11:50:39 2001
@@ -5,18 +5,21 @@
 #
 # Code maturity level options
 #
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
 
 #
 # Machine selection
 #
 CONFIG_SGI_IP22=y
 # CONFIG_SGI_IP27 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF32=y
 CONFIG_ARC32=y
 CONFIG_BOARD_SCACHE=y
 CONFIG_ARC_MEMORY=y
 CONFIG_SGI=y
+CONFIG_L1_CACHE_SHIFT=5
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_PCI is not set
@@ -37,20 +40,25 @@
 # General setup
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_MIPS_FPU_EMULATOR is not set
 CONFIG_NET=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_ARC_CONSOLE is not set
 CONFIG_BINFMT_ELF=y
-# CONFIG_MIPS32_COMPAT is not set
+CONFIG_MIPS32_COMPAT=y
+CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_MISC is not set
 
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Memory Technology Devices (MTD)
@@ -58,6 +66,11 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
@@ -85,21 +98,30 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
 
 #
 #  
@@ -108,6 +130,14 @@
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
@@ -130,7 +160,66 @@
 #
 # SCSI support
 #
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_SGIWD93_SCSI=y
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
 
 #
 # I2O device support
@@ -154,21 +243,33 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 # CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
-# CONFIG_NET_ETHERNET is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+CONFIG_SGISEEQ=y
 
 #
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
 # CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
-# CONFIG_PLIP is not set
+# CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -182,12 +283,13 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
 
 #
 # Wan interfaces
 #
 # CONFIG_WAN is not set
-CONFIG_SGISEEQ=y
 
 #
 # Amateur Radio support
@@ -217,9 +319,8 @@
 # CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 
 #
 # I2C support
@@ -269,8 +370,8 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_ADFS_FS is not set
@@ -285,10 +386,12 @@
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
@@ -296,7 +399,7 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
@@ -315,7 +418,7 @@
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
@@ -333,14 +436,31 @@
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
 #
 # Console drivers
 #
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
 CONFIG_SGI_NEWPORT_CONSOLE=y
 CONFIG_FONT_8x16=y
 CONFIG_KCORE_ELF=y
@@ -353,8 +473,10 @@
 #
 # SGI devices
 #
-# CONFIG_SGI_SERIAL is not set
+CONFIG_SGI_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_SGI_DS1286=y
+# CONFIG_SGI_NEWPORT_GFX is not set
 
 #
 # USB support
@@ -370,5 +492,7 @@
 # Kernel hacking
 #
 CONFIG_CROSSCOMPILE=y
+# CONFIG_MIPS_FPE_MODULE is not set
 # CONFIG_REMOTE_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/defconfig-ip27 linux/arch/mips64/defconfig-ip27
--- v2.4.6/linux/arch/mips64/defconfig-ip27	Fri Apr 13 20:26:07 2001
+++ linux/arch/mips64/defconfig-ip27	Wed Jul  4 11:50:39 2001
@@ -14,16 +14,19 @@
 CONFIG_SGI_IP27=y
 # CONFIG_SGI_SN0_N_MODE is not set
 CONFIG_DISCONTIGMEM=y
-# CONFIG_NUMA is not set
+CONFIG_NUMA=y
 # CONFIG_MAPPED_KERNEL is not set
 # CONFIG_REPLICATE_KTEXT is not set
 # CONFIG_REPLICATE_EXHANDLERS is not set
 CONFIG_SMP=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BOOT_ELF64=y
 CONFIG_ARC64=y
 CONFIG_COHERENT_IO=y
 CONFIG_PCI=y
 CONFIG_QL_ISP_A64=y
+CONFIG_L1_CACHE_SHIFT=7
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
@@ -68,6 +71,11 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
@@ -95,19 +103,24 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 
@@ -187,8 +200,6 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
@@ -254,7 +265,6 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -302,9 +312,8 @@
 CONFIG_SERIAL_CONSOLE=y
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
 
 #
 # I2C support
@@ -370,10 +379,12 @@
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
@@ -381,7 +392,7 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
@@ -458,3 +469,4 @@
 CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/binfmt_elf32.c linux/arch/mips64/kernel/binfmt_elf32.c
--- v2.4.6/linux/arch/mips64/kernel/binfmt_elf32.c	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips64/kernel/binfmt_elf32.c	Wed Jul  4 11:50:39 2001
@@ -1,8 +1,8 @@
 /*
  * Support for 32-bit Linux/MIPS ELF binaries.
  *
- * Copyright (C) 1999 Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2001 Ralf Baechle
+ * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
  *
  * Heavily inspired by the 32-bit Sparc compat code which is
  * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
@@ -28,7 +28,7 @@
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #define elf_check_arch(x)	\
-	((x)->e_machine == EM_MIPS || (x)->e_machine == EM_MIPS_RS4_BE)
+	((x)->e_machine == EM_MIPS)
 
 #define TASK32_SIZE		0x80000000UL
 #undef ELF_ET_DYN_BASE
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/branch.c linux/arch/mips64/kernel/branch.c
--- v2.4.6/linux/arch/mips64/kernel/branch.c	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/kernel/branch.c	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: branch.c,v 1.1 1999/10/09 20:55:05 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -66,7 +65,7 @@
 		switch (insn.i_format.rt) {
 	 	case bltz_op:
 		case bltzl_op:
-			if (regs->regs[insn.i_format.rs] < 0)
+			if ((long)regs->regs[insn.i_format.rs] < 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -75,7 +74,7 @@
 
 		case bgez_op:
 		case bgezl_op:
-			if (regs->regs[insn.i_format.rs] >= 0)
+			if ((long)regs->regs[insn.i_format.rs] >= 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -85,7 +84,7 @@
 		case bltzal_op:
 		case bltzall_op:
 			regs->regs[31] = epc + 8;
-			if (regs->regs[insn.i_format.rs] < 0)
+			if ((long)regs->regs[insn.i_format.rs] < 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -95,7 +94,7 @@
 		case bgezal_op:
 		case bgezall_op:
 			regs->regs[31] = epc + 8;
-			if (regs->regs[insn.i_format.rs] >= 0)
+			if ((long)regs->regs[insn.i_format.rs] >= 0)
 				epc = epc + 4 + (insn.i_format.simmediate << 2);
 			else
 				epc += 8;
@@ -143,7 +142,7 @@
 	case blez_op: /* not really i_format */
 	case blezl_op:
 		/* rt field assumed to be zero */
-		if (regs->regs[insn.i_format.rs] <= 0)
+		if ((long)regs->regs[insn.i_format.rs] <= 0)
 			epc = epc + 4 + (insn.i_format.simmediate << 2);
 		else
 			epc += 8;
@@ -153,7 +152,7 @@
 	case bgtz_op:
 	case bgtzl_op:
 		/* rt field assumed to be zero */
-		if (regs->regs[insn.i_format.rs] > 0)
+		if ((long)regs->regs[insn.i_format.rs] > 0)
 			epc = epc + 4 + (insn.i_format.simmediate << 2);
 		else
 			epc += 8;
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/entry.S linux/arch/mips64/kernel/entry.S
--- v2.4.6/linux/arch/mips64/kernel/entry.S	Fri Aug  4 16:15:37 2000
+++ linux/arch/mips64/kernel/entry.S	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: entry.S,v 1.5 2000/02/23 00:41:00 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/head.S linux/arch/mips64/kernel/head.S
--- v2.4.6/linux/arch/mips64/kernel/head.S	Wed Jul 12 15:14:41 2000
+++ linux/arch/mips64/kernel/head.S	Wed Jul  4 11:50:39 2001
@@ -33,6 +33,7 @@
 #endif
 	.endm
 
+#ifdef CONFIG_SGI_IP27
 	/*
 	 * outputs the local nasid into t1.
 	 */
@@ -42,6 +43,7 @@
 	and	t1, NSRI_NODEID_MASK
 	dsrl	t1, NSRI_NODEID_SHFT
 	.endm
+#endif /* CONFIG_SGI_IP27 */
 
 	/*
 	 * inputs are the text nasid in t1, data nasid in t2.
@@ -94,9 +96,11 @@
 	ori	sp, 0xf				# align stack on 16 byte.
 	xori	sp, 0xf
 
+#ifdef CONFIG_SGI_IP27
 	GET_NASID_ASM
 	move	t2, t1				# text and data are here
 	MAPPED_KERNEL_SETUP_TLB
+#endif /* IP27 */
 
 	ARC64_TWIDDLE_PC
 
@@ -131,6 +135,7 @@
 1:	b	1b				# just in case ...
 	END(kernel_entry)
 
+#ifdef CONFIG_SGI_IP27
 NESTED(bootstrap, 16, sp)
 	GET_NASID_ASM
 	li	t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + KLDIR_OFF_POINTER + K0BASE
@@ -149,6 +154,7 @@
 	mtc0	t0, CP0_STATUS			   # thread in copy_thread.
 	jal	cboot
 	END(bootstrap)
+#endif /* CONFIG_SGI_IP27 */
 
 	__FINIT
 
@@ -170,8 +176,6 @@
 	page	swapper_pg_dir, 1
 	page	invalid_pte_table, 0
 	page	invalid_pmd_table, 1
-	page	empty_bad_page_table, 0
-	page	empty_bad_pmd_table, 1
 	page	kptbl, KPTBL_PAGE_ORDER
 	.globl	ekptbl
 	page	kpmdtbl, 0
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/ioctl32.c linux/arch/mips64/kernel/ioctl32.c
--- v2.4.6/linux/arch/mips64/kernel/ioctl32.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/kernel/ioctl32.c	Wed Jul  4 11:50:39 2001
@@ -7,6 +7,7 @@
  *
  * Mostly stolen from the sparc64 ioctl32 implementation.
  */
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
@@ -25,6 +26,7 @@
 #include <linux/elevator.h>
 #include <linux/auto_fs.h>
 #include <linux/ext2_fs.h>
+#include <linux/raid/md_u.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
@@ -67,6 +69,24 @@
 	int tv_usec;
 };
 
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct timeval32 *up = (struct timeval32 *)arg;
+	struct timeval ktv;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+	set_fs(old_fs);
+	if (!err) {
+		err = put_user(ktv.tv_sec, &up->tv_sec);
+		err |= __put_user(ktv.tv_usec, &up->tv_usec);
+	}
+
+	return err;
+}
+
 #define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
 #define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
 #define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
@@ -108,6 +128,8 @@
         __kernel_caddr_t32  ifcbuf;
 };
 
+#ifdef CONFIG_NET
+
 static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ireq32 *uir32 = (struct ireq32 *)arg;
@@ -308,6 +330,8 @@
 	return ret;
 }
 
+#endif /* CONFIG_NET */
+
 static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	/* These are just misnamed, they actually get/put from/to user an int */
@@ -364,6 +388,11 @@
 	return error;
 }
 
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
 struct blkpg_ioctl_arg32 {
 	int op;
 	int flags;
@@ -634,6 +663,27 @@
 	IOCTL32_DEFAULT(VT_LOCKSWITCH),
 	IOCTL32_DEFAULT(VT_UNLOCKSWITCH),
 
+#ifdef CONFIG_NET
+	/* Socket level stuff */
+	IOCTL32_DEFAULT(FIOSETOWN),
+	IOCTL32_DEFAULT(SIOCSPGRP),
+	IOCTL32_DEFAULT(FIOGETOWN),
+	IOCTL32_DEFAULT(SIOCGPGRP),
+	IOCTL32_DEFAULT(SIOCATMARK),
+	IOCTL32_DEFAULT(SIOCSIFLINK),
+	IOCTL32_DEFAULT(SIOCSIFENCAP),
+	IOCTL32_DEFAULT(SIOCGIFENCAP),
+	IOCTL32_DEFAULT(SIOCSIFBR),
+	IOCTL32_DEFAULT(SIOCGIFBR),
+	IOCTL32_DEFAULT(SIOCSARP),
+	IOCTL32_DEFAULT(SIOCGARP),
+	IOCTL32_DEFAULT(SIOCDARP),
+	IOCTL32_DEFAULT(SIOCSRARP),
+	IOCTL32_DEFAULT(SIOCGRARP),
+	IOCTL32_DEFAULT(SIOCDRARP),
+	IOCTL32_DEFAULT(SIOCADDDLCI),
+	IOCTL32_DEFAULT(SIOCDELDLCI),
+
 	IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
 	IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
 	IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
@@ -665,6 +715,14 @@
 	IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc),
 	IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
 	IOCTL32_HANDLER(SIOCDELRT, routing_ioctl),
+	/*
+	 * Note SIOCRTMSG is no longer, so this is safe and * the user would
+	 * have seen just an -EINVAL anyways.
+	 */
+	IOCTL32_HANDLER(SIOCRTMSG, ret_einval),
+	IOCTL32_HANDLER(SIOCGSTAMP, do_siocgstamp),
+
+#endif /* CONFIG_NET */
 
 	IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
 	IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
@@ -712,6 +770,34 @@
 	IOCTL32_HANDLER(BLKPG, blkpg_ioctl_trans),
 	IOCTL32_DEFAULT(BLKELVGET),
 	IOCTL32_DEFAULT(BLKELVSET),
+
+#ifdef CONFIG_MD
+	/* status */
+	IOCTL32_DEFAULT(RAID_VERSION),
+	IOCTL32_DEFAULT(GET_ARRAY_INFO),
+	IOCTL32_DEFAULT(GET_DISK_INFO),
+	IOCTL32_DEFAULT(PRINT_RAID_DEBUG),
+	IOCTL32_DEFAULT(RAID_AUTORUN),
+
+	/* configuration */
+	IOCTL32_DEFAULT(CLEAR_ARRAY),
+	IOCTL32_DEFAULT(ADD_NEW_DISK),
+	IOCTL32_DEFAULT(HOT_REMOVE_DISK),
+	IOCTL32_DEFAULT(SET_ARRAY_INFO),
+	IOCTL32_DEFAULT(SET_DISK_INFO),
+	IOCTL32_DEFAULT(WRITE_RAID_INFO),
+	IOCTL32_DEFAULT(UNPROTECT_ARRAY),
+	IOCTL32_DEFAULT(PROTECT_ARRAY),
+	IOCTL32_DEFAULT(HOT_ADD_DISK),
+	IOCTL32_DEFAULT(SET_DISK_FAULTY),
+
+	/* usage */
+	IOCTL32_DEFAULT(RUN_ARRAY),
+	IOCTL32_DEFAULT(START_ARRAY),
+	IOCTL32_DEFAULT(STOP_ARRAY),
+	IOCTL32_DEFAULT(STOP_ARRAY_RO),
+	IOCTL32_DEFAULT(RESTART_ARRAY_RW),
+#endif /* CONFIG_MD */
 
 	IOCTL32_DEFAULT(MTIOCTOP),			/* mtio.h ioctls  */
 	IOCTL32_HANDLER(MTIOCGET32, mt_ioctl_trans),
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/linux32.c linux/arch/mips64/kernel/linux32.c
--- v2.4.6/linux/arch/mips64/kernel/linux32.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/mips64/kernel/linux32.c	Wed Jul  4 11:50:39 2001
@@ -742,7 +742,9 @@
 	set_fs (KERNEL_DS);
 	ret = sys_getrusage(who, &r);
 	set_fs (old_fs);
-	if (put_rusage (ru, &r)) return -EFAULT;
+	if (put_rusage (ru, &r))
+		return -EFAULT;
+
 	return ret;
 }
 
@@ -752,7 +754,6 @@
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 		(__get_user(o->tv_sec, &i->tv_sec) |
 		 __get_user(o->tv_usec, &i->tv_usec)));
-	return ENOSYS;
 }
 
 static inline long
@@ -763,7 +764,6 @@
 		 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
 		 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
 		 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
-	return ENOSYS;
 }
 
 static inline long
@@ -777,12 +777,11 @@
 static inline long
 put_it32(struct itimerval32 *o, struct itimerval *i)
 {
-	return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
 		 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
 		 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
 		 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
-	return ENOSYS;
 }
 
 extern int do_getitimer(int which, struct itimerval *value);
@@ -839,6 +838,7 @@
 	/* And we'd better return too much than too little anyway */
 	if (it_old.it_value.tv_usec)
 		oldalarm++;
+
 	return oldalarm;
 }
 
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/mips64_ksyms.c linux/arch/mips64/kernel/mips64_ksyms.c
--- v2.4.6/linux/arch/mips64/kernel/mips64_ksyms.c	Fri Mar  2 11:15:47 2001
+++ linux/arch/mips64/kernel/mips64_ksyms.c	Wed Jul  4 11:50:39 2001
@@ -5,8 +5,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -90,16 +90,11 @@
 EXPORT_SYMBOL(invalid_pte_table);
 
 /*
- * Semaphore stuff
- */
-EXPORT_SYMBOL(__down_read);
-EXPORT_SYMBOL(__down_write);
-EXPORT_SYMBOL(__rwsem_wake);
-
-/*
  * Base address of ports for Intel style I/O.
  */
+#if defined (CONFIG_PCI) || defined (CONFIG_ISA)
 EXPORT_SYMBOL(mips_io_port_base);
+#endif
 
 /*
  * Kernel hacking ...
@@ -121,4 +116,4 @@
 #endif
 
 EXPORT_SYMBOL(get_wchan);
-EXPORT_SYMBOL(flush_tlb_page);
+EXPORT_SYMBOL(_flush_tlb_page);
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/proc.c linux/arch/mips64/kernel/proc.c
--- v2.4.6/linux/arch/mips64/kernel/proc.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/kernel/proc.c	Wed Jul  4 11:50:39 2001
@@ -26,67 +26,50 @@
  * Currently /proc/cpuinfo is being abused to print data about the
  * number of date/instruction cacheflushes.
  */
-int get_cpuinfo(char *buffer, char **start, off_t offset, int count)
+int get_cpuinfo(char *buffer)
 {
 	char fmt [64];
-	struct cpuinfo_mips *c = cpu_data;
-	size_t len = 0;
-  int n;
+	size_t len;
 
-  for (n = 0; n < smp_num_cpus; n++, c++) {
-		len += sprintf(buffer + len, "processor\t\t: %d\n", n);
-		len += sprintf(buffer + len, "vendor_id\t\t: MIPS\n");
-		len += sprintf(buffer + len, "model name\t\t: R10000\n");
-/*		len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n",
+	len = sprintf(buffer, "cpu\t\t\t: MIPS\n");
+#if 0
+	len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n",
 	               cpu_name[mips_cputype <= CPU_LAST ?
 	                        mips_cputype :
 	                        CPU_UNKNOWN],
 	               (version >> 4) & 0x0f,
 	               version & 0x0f);
-		len += sprintf(buffer + len, "system type\t\t: %s %s\n",
+	len += sprintf(buffer + len, "system type\t\t: %s %s\n",
 		       mach_group_names[mips_machgroup],
 		       mach_group_to_name[mips_machgroup][mips_machtype]);
-*/
-		len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n",
-		       (loops_per_sec + 2500) / 500000,
-	               ((loops_per_sec + 2500) / 5000) % 100);
-/*		len += sprintf(buffer + len, "Number of cpus\t\t: %d\n", smp_num_cpus);*/
+#endif
+	len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n",
+		       (loops_per_jiffy + 2500) / (500000/HZ),
+	               ((loops_per_jiffy + 2500) / (5000/HZ)) % 100);
+	len += sprintf(buffer + len, "Number of cpus\t\t: %d\n", smp_num_cpus);
 #if defined (__MIPSEB__)
-		len += sprintf(buffer + len, "byteorder\t\t: big endian\n");
+	len += sprintf(buffer + len, "byteorder\t\t: big endian\n");
 #endif
 #if defined (__MIPSEL__)
-		len += sprintf(buffer + len, "byteorder\t\t: little endian\n");
+	len += sprintf(buffer + len, "byteorder\t\t: little endian\n");
 #endif
-		len += sprintf(buffer + len, "unaligned accesses\t: %lu\n",
+	len += sprintf(buffer + len, "unaligned accesses\t: %lu\n",
 		       unaligned_instructions);
-		len += sprintf(buffer + len, "wait instruction\t: %s\n",
+	len += sprintf(buffer + len, "wait instruction\t: %s\n",
 	               wait_available ? "yes" : "no");
-		len += sprintf(buffer + len, "microsecond timers\t: %s\n",
+	len += sprintf(buffer + len, "microsecond timers\t: %s\n",
 	               cyclecounter_available ? "yes" : "no");
-		len += sprintf(buffer + len, "extra interrupt vector\t: %s\n",
+	len += sprintf(buffer + len, "extra interrupt vector\t: %s\n",
 	               dedicated_iv_available ? "yes" : "no");
-		len += sprintf(buffer + len, "hardware watchpoint\t: %s\n",
+	len += sprintf(buffer + len, "hardware watchpoint\t: %s\n",
 	               watch_available ? "yes" : "no");
 
-		sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
+	sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
 	        vce_available ? "%d" : "not available");
-		len += sprintf(buffer + len, fmt, 'D', vced_count);
-		len += sprintf(buffer + len, fmt, 'I', vcei_count);
-		len += sprintf(buffer + len, "\n");
-
-		if (len < offset)
-			offset -= len, len = 0;
-		else if (len >= offset + count)
-			goto leave_loop;
-	}
-
-leave_loop:
-	*start = buffer + offset;
-	len -= offset;
-	if (len < 0)
-		len = 0;
-	return len > count ? count : len;
+	len += sprintf(buffer + len, fmt, 'D', vced_count);
+	len += sprintf(buffer + len, fmt, 'I', vcei_count);
 
+	return len;
 }
 
 void init_irq_proc(void)
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/r4k_fpu.S linux/arch/mips64/kernel/r4k_fpu.S
--- v2.4.6/linux/arch/mips64/kernel/r4k_fpu.S	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/kernel/r4k_fpu.S	Wed Jul  4 11:50:39 2001
@@ -1,17 +1,16 @@
-/* $Id: r4k_fpu.S,v 1.1 1999/09/27 16:01:38 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Save/restore floating point context for signal handlers.
  *
- * Copyright (C) 1996, 1998, 1999 by Ralf Baechle
+ * Copyright (C) 1996, 1998, 1999, 2001 by Ralf Baechle
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
  */
 #include <asm/asm.h>
 #include <asm/errno.h>
@@ -33,11 +32,11 @@
 	.set	noreorder
 	/* Save floating point context */
 LEAF(save_fp_context)
-	mfc0	t1,CP0_STATUS
-	 sll	t2,t1,5
+	mfc0	t1, CP0_STATUS
+	sll	t2, t1,5
 
-	bgez	t2,1f
-	 cfc1	t1,fcr31
+	bgez	t2, 1f
+	 cfc1	t1, fcr31
 	/* Store the 16 odd double precision registers */
 	EX	sdc1 $f1, SC_FPREGS+8(a0)
 	EX	sdc1 $f3, SC_FPREGS+24(a0)
@@ -75,8 +74,8 @@
 	EX	sdc1 $f28, SC_FPREGS+224(a0)
 	EX	sdc1 $f30, SC_FPREGS+240(a0)
 	EX	sw t1, SC_FPC_CSR(a0)
-	cfc1	t0,$0				# implementation/version
-	EX	sw t0,SC_FPC_EIR(a0)
+	cfc1	t0, $0				# implementation/version
+	EX	sw t0, SC_FPC_EIR(a0)
 
 	jr	ra
 	 li	v0, 0					# success
@@ -93,8 +92,8 @@
  */
 LEAF(restore_fp_context)
 	mfc0	t1, CP0_STATUS
-	sll	t0,t1,5
-	bgez	t0,1f
+	sll	t0, t1,5
+	bgez	t0, 1f
 	 EX	lw t0, SC_FPC_CSR(a0)
 
 	/* Restore the 16 odd double precision registers only
@@ -137,13 +136,13 @@
 	EX	ldc1 $f26, SC_FPREGS+208(a0)
 	EX	ldc1 $f28, SC_FPREGS+224(a0)
 	EX	ldc1 $f30, SC_FPREGS+240(a0)
-	ctc1	t0,fcr31
+	ctc1	t0, fcr31
 	jr	ra
 	 li	v0, 0					# success
 	END(restore_fp_context)
 
 	.type	fault@function
 	.ent	fault
-fault:	li	v0, -EFAULT
-	jr	ra
+fault:	jr	ra
+	 li	v0, -EFAULT				# failure
 	.end	fault
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/r4k_tlb.S linux/arch/mips64/kernel/r4k_tlb.S
--- v2.4.6/linux/arch/mips64/kernel/r4k_tlb.S	Wed Jul 12 15:14:41 2000
+++ linux/arch/mips64/kernel/r4k_tlb.S	Wed Jul  4 11:50:39 2001
@@ -24,7 +24,7 @@
 
 	.macro	LOAD_PTE2, ptr, tmp
 #ifdef CONFIG_SMP
-	mfc0	\tmp, CP0_CONTEXT
+	dmfc0	\tmp, CP0_CONTEXT
 	dla	\ptr, pgd_current
 	dsrl	\tmp, 23
 	daddu	\ptr, \tmp
@@ -96,9 +96,6 @@
 	 */
 	dmfc0	k0, CP0_BADVADDR
 	dli	k1, VMALLOC_START
-	sltu	k1, k0, k1
-	bne	k1, zero, not_vmalloc
-	 dli	k1, VMALLOC_START
 
 	/*
 	 * Now find offset into kptbl.
@@ -114,20 +111,16 @@
 	 */
 	dla	k0, ekptbl
 	sltu	k0, k1, k0
-	beq	k0, zero, not_vmalloc
+	beqz	k0, not_vmalloc
 
 	/*
 	 * Load cp0 registers.
 	 */
 	ld	k0, 0(k1)			# get even pte
 	ld	k1, 8(k1)			# get odd pte
-1:
+
+not_vmalloc:
 	PTE_RELOAD k0 k1
 	nop
 	tlbwr
 	eret
-not_vmalloc:
-	daddu	k0, zero, zero
-	daddu	k1, zero, zero
-	j	1b
-	nop
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/scall_64.S linux/arch/mips64/kernel/scall_64.S
--- v2.4.6/linux/arch/mips64/kernel/scall_64.S	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/kernel/scall_64.S	Wed Jul  4 11:50:39 2001
@@ -63,8 +63,14 @@
 1:	sd	v0, PT_R2(sp)		# result
 
 FEXPORT(ret_from_sys_call_64)
-	lw	t0, irq_stat		# softirq_active
-	lw	t1, irq_stat+4		# softirq_mask.  unused delay slot
+	la	t1, irq_stat		# softirq_active
+#ifdef CONFIG_SMP
+	lwu	t0, TASK_PROCESSOR($28)
+	dsll	t0, t0, 5
+	daddu	t1, t0
+#endif
+	lw	t0, 0(t1)		# softirq_active
+	lw	t1, 4(t1)		# softirq_mask.  unused delay slot
 	and	t0, t1
 	bnez	t0, handle_softirq_64
 
@@ -131,217 +137,217 @@
 	END(handle_sys64)
 
 sys_call_table:
-	PTR	sys_syscall				/* 4000 */
+	PTR	sys_syscall				/* 5000 */
 	PTR	sys_exit
 	PTR	sys_fork
 	PTR	sys_read
 	PTR	sys_write
-	PTR	sys_open				/* 4005 */
+	PTR	sys_open				/* 5005 */
 	PTR	sys_close
 	PTR	sys_waitpid
 	PTR	sys_creat
 	PTR	sys_link
-	PTR	sys_unlink				/* 4010 */
+	PTR	sys_unlink				/* 5010 */
 	PTR	sys_execve
 	PTR	sys_chdir
 	PTR	sys_time
 	PTR	sys_mknod
-	PTR	sys_chmod				/* 4015 */
+	PTR	sys_chmod				/* 5015 */
 	PTR	sys_lchown
 	PTR	sys_ni_syscall
 	PTR	sys_stat
 	PTR	sys_lseek
-	PTR	sys_getpid				/* 4020 */
+	PTR	sys_getpid				/* 5020 */
 	PTR	sys_mount
 	PTR	sys_oldumount
 	PTR	sys_setuid
 	PTR	sys_getuid
-	PTR	sys_stime				/* 4025 */
+	PTR	sys_stime				/* 5025 */
 	PTR	sys_ni_syscall		/* ptrace */
 	PTR	sys_alarm
 	PTR	sys_fstat
 	PTR	sys_pause
-	PTR	sys_utime				/* 4030 */
+	PTR	sys_utime				/* 5030 */
 	PTR	sys_ni_syscall
 	PTR	sys_ni_syscall
 	PTR	sys_access
 	PTR	sys_nice
-	PTR	sys_ni_syscall				/* 4035 */
+	PTR	sys_ni_syscall				/* 5035 */
 	PTR	sys_sync
 	PTR	sys_kill
 	PTR	sys_rename
 	PTR	sys_mkdir
-	PTR	sys_rmdir				/* 4040 */
+	PTR	sys_rmdir				/* 5040 */
 	PTR	sys_dup
 	PTR	sys_pipe
 	PTR	sys_times
 	PTR	sys_ni_syscall
-	PTR	sys_brk					/* 4045 */
+	PTR	sys_brk					/* 5045 */
 	PTR	sys_setgid
 	PTR	sys_getgid
 	PTR	sys_ni_syscall		/* was signal	2 */
 	PTR	sys_geteuid
-	PTR	sys_getegid				/* 4050 */
+	PTR	sys_getegid				/* 5050 */
 	PTR	sys_acct
 	PTR	sys_umount
 	PTR	sys_ni_syscall
 	PTR	sys_ioctl
-	PTR	sys_fcntl				/* 4055 */
+	PTR	sys_fcntl				/* 5055 */
 	PTR	sys_ni_syscall
 	PTR	sys_setpgid
 	PTR	sys_ni_syscall
 	PTR	sys_ni_syscall
-	PTR	sys_umask				/* 4060 */
+	PTR	sys_umask				/* 5060 */
 	PTR	sys_chroot
 	PTR	sys_ustat
 	PTR	sys_dup2
 	PTR	sys_getppid
-	PTR	sys_getpgrp				/* 4065 */
+	PTR	sys_getpgrp				/* 5065 */
 	PTR	sys_setsid
 	PTR	sys_sigaction
 	PTR	sys_sgetmask
 	PTR	sys_ssetmask
-	PTR	sys_setreuid				/* 4070 */
+	PTR	sys_setreuid				/* 5070 */
 	PTR	sys_setregid
 	PTR	sys_sigsuspend
 	PTR	sys_sigpending
 	PTR	sys_sethostname
-	PTR	sys_setrlimit				/* 4075 */
+	PTR	sys_setrlimit				/* 5075 */
 	PTR	sys_getrlimit
 	PTR	sys_getrusage
 	PTR	sys_gettimeofday
 	PTR	sys_settimeofday
-	PTR	sys_getgroups				/* 4080 */
+	PTR	sys_getgroups				/* 5080 */
 	PTR	sys_setgroups
 	PTR	sys_ni_syscall			/* old_select */
 	PTR	sys_symlink
 	PTR	sys_lstat
-	PTR	sys_readlink				/* 4085 */
+	PTR	sys_readlink				/* 5085 */
 	PTR	sys_uselib
 	PTR	sys_swapon
 	PTR	sys_reboot
 	PTR	sys_ni_syscall			/* old_readdir */
-	PTR	sys_mmap				/* 4090 */
+	PTR	sys_mmap				/* 5090 */
 	PTR	sys_munmap
 	PTR	sys_truncate
 	PTR	sys_ftruncate
 	PTR	sys_fchmod
-	PTR	sys_fchown				/* 4095 */
+	PTR	sys_fchown				/* 5095 */
 	PTR	sys_getpriority
 	PTR	sys_setpriority
 	PTR	sys_ni_syscall
 	PTR	sys_statfs
-	PTR	sys_fstatfs				/* 4100 */
+	PTR	sys_fstatfs				/* 5100 */
 	PTR	sys_ni_syscall		/* sys_ioperm */
 	PTR	sys_socketcall
 	PTR	sys_syslog
 	PTR	sys_setitimer
-	PTR	sys_getitimer				/* 4105 */
+	PTR	sys_getitimer				/* 5105 */
 	PTR	sys_newstat
 	PTR	sys_newlstat
 	PTR	sys_newfstat
 	PTR	sys_ni_syscall
-	PTR	sys_ni_syscall		/* sys_ioperm  *//* 4110 */
+	PTR	sys_ni_syscall		/* sys_ioperm  *//* 5110 */
 	PTR	sys_vhangup
 	PTR	sys_ni_syscall		/* was sys_idle	 */
 	PTR	sys_ni_syscall		/* sys_vm86 */
 	PTR	sys_wait4
-	PTR	sys_swapoff				/* 4115 */
+	PTR	sys_swapoff				/* 5115 */
 	PTR	sys_sysinfo
 	PTR	sys_ipc
 	PTR	sys_fsync
 	PTR	sys_sigreturn
-	PTR	sys_clone				/* 4120 */
+	PTR	sys_clone				/* 5120 */
 	PTR	sys_setdomainname
 	PTR	sys_newuname
 	PTR	sys_ni_syscall		/* sys_modify_ldt */
 	PTR	sys_adjtimex
-	PTR	sys_mprotect				/* 4125 */
+	PTR	sys_mprotect				/* 5125 */
 	PTR	sys_sigprocmask
 	PTR	sys_create_module
 	PTR	sys_init_module
 	PTR	sys_delete_module
-	PTR	sys_get_kernel_syms 			/* 4130 */
+	PTR	sys_get_kernel_syms 			/* 5130 */
 	PTR	sys_quotactl
 	PTR	sys_getpgid
 	PTR	sys_fchdir
 	PTR	sys_bdflush
-	PTR	sys_sysfs				/* 4135 */
+	PTR	sys_sysfs				/* 5135 */
 	PTR	sys_personality
 	PTR	sys_ni_syscall		/* for afs_syscall */
 	PTR	sys_setfsuid
 	PTR	sys_setfsgid
-	PTR	sys_llseek				/* 4140 */
+	PTR	sys_llseek				/* 5140 */
 	PTR	sys_getdents
 	PTR	sys_select
 	PTR	sys_flock
 	PTR	sys_msync
-	PTR	sys_readv				/* 4145 */
+	PTR	sys_readv				/* 5145 */
 	PTR	sys_writev
 	PTR	sys_cacheflush
 	PTR	sys_cachectl
 	PTR	sys_sysmips
-	PTR	sys_ni_syscall				/* 4150 */
+	PTR	sys_ni_syscall				/* 5150 */
 	PTR	sys_getsid
 	PTR	sys_fdatasync
 	PTR	sys_sysctl
 	PTR	sys_mlock
-	PTR	sys_munlock				/* 4155 */
+	PTR	sys_munlock				/* 5155 */
 	PTR	sys_mlockall
 	PTR	sys_munlockall
 	PTR	sys_sched_setparam
 	PTR	sys_sched_getparam
-	PTR	sys_sched_setscheduler			/* 4160 */
+	PTR	sys_sched_setscheduler			/* 5160 */
 	PTR	sys_sched_getscheduler
 	PTR	sys_sched_yield
 	PTR	sys_sched_get_priority_max
 	PTR	sys_sched_get_priority_min
-	PTR	sys_sched_rr_get_interval		/* 4165 */
+	PTR	sys_sched_rr_get_interval		/* 5165 */
 	PTR	sys_nanosleep
 	PTR	sys_mremap
 	PTR	sys_accept
 	PTR	sys_bind
-	PTR	sys_connect				/* 4170 */
+	PTR	sys_connect				/* 5170 */
 	PTR	sys_getpeername
 	PTR	sys_getsockname
 	PTR	sys_getsockopt
 	PTR	sys_listen
-	PTR	sys_recv				/* 4175 */
+	PTR	sys_recv				/* 5175 */
 	PTR	sys_recvfrom
 	PTR	sys_recvmsg
 	PTR	sys_send
 	PTR	sys_sendmsg
-	PTR	sys_sendto				/* 4180 */
+	PTR	sys_sendto				/* 5180 */
 	PTR	sys_setsockopt
 	PTR	sys_shutdown
 	PTR	sys_socket
 	PTR	sys_socketpair
-	PTR	sys_setresuid				/* 4185 */
+	PTR	sys_setresuid				/* 5185 */
 	PTR	sys_getresuid
 	PTR	sys_query_module
 	PTR	sys_poll
 	PTR	sys_nfsservctl
-	PTR	sys_setresgid				/* 4190 */
+	PTR	sys_setresgid				/* 5190 */
 	PTR	sys_getresgid
 	PTR	sys_prctl
 	PTR	sys_rt_sigreturn
 	PTR	sys_rt_sigaction
-	PTR	sys_rt_sigprocmask 			/* 4195 */
+	PTR	sys_rt_sigprocmask 			/* 5195 */
 	PTR	sys_rt_sigpending
 	PTR	sys_rt_sigtimedwait
 	PTR	sys_rt_sigqueueinfo
 	PTR	sys_rt_sigsuspend
-	PTR	sys_pread				/* 4200 */
+	PTR	sys_pread				/* 5200 */
 	PTR	sys_pwrite
 	PTR	sys_chown
 	PTR	sys_getcwd
 	PTR	sys_capget
-	PTR	sys_capset				/* 4205 */
+	PTR	sys_capset				/* 5205 */
 	PTR	sys_sigaltstack
 	PTR	sys_sendfile
 	PTR	sys_ni_syscall
 	PTR	sys_ni_syscall
-	PTR	sys_pivot_root				/* 4210 */
+	PTR	sys_pivot_root				/* 5210 */
 	PTR	sys_mincore
 	PTR	sys_madvise
 	PTR	sys_getdents64
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/scall_o32.S linux/arch/mips64/kernel/scall_o32.S
--- v2.4.6/linux/arch/mips64/kernel/scall_o32.S	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/kernel/scall_o32.S	Wed Jul  4 11:50:39 2001
@@ -76,8 +76,14 @@
 1:	sd	v0, PT_R2(sp)		# result
 	
 FEXPORT(o32_ret_from_sys_call)
-	lw	t0, irq_stat		# softirq_active
-	lw	t1, irq_stat+4		# softirq_mask.  unused delay slot
+	la	t1, irq_stat		# softirq_active
+#ifdef CONFIG_SMP
+	lwu	t0, TASK_PROCESSOR($28)
+	dsll	t0, t0, 5
+	daddu	t1, t0
+#endif
+	lw	t0, 0(t1)		# softirq_active
+	lw	t1, 4(t1)		# softirq_mask.  unused delay slot
 	and	t0, t1
 	bnez	t0, o32_handle_softirq
 
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/setup.c linux/arch/mips64/kernel/setup.c
--- v2.4.6/linux/arch/mips64/kernel/setup.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/mips64/kernel/setup.c	Wed Jul  4 11:50:39 2001
@@ -31,7 +31,6 @@
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
 #include <asm/cpu.h>
-#include <asm/io.h>
 #include <asm/stackframe.h>
 #include <asm/system.h>
 #include <asm/pgalloc.h>
@@ -56,8 +55,6 @@
  */
 char cyclecounter_available;
 
-unsigned long loops_per_sec;
-
 /*
  * Set if box has EISA slots.
  */
@@ -89,8 +86,9 @@
 unsigned long mips_machtype = MACH_UNKNOWN;
 unsigned long mips_machgroup = MACH_GROUP_UNKNOWN;
 
+struct boot_mem_map boot_mem_map;
+
 unsigned char aux_device_present;
-extern int _end;
 
 extern void load_mmu(void);
 
@@ -98,15 +96,6 @@
        char saved_command_line[CL_SIZE];
 extern char arcs_cmdline[CL_SIZE];
 
-/*
- * mips_io_port_base is the begin of the address space to which x86 style
- * I/O ports are mapped.
- */
-#ifdef CONFIG_SGI_IP27
-/* XXX Origin garbage has no business in this file  */
-unsigned long mips_io_port_base = IO_BASE;
-#endif
-
 extern void ip22_setup(void);
 extern void ip27_setup(void);
 
@@ -137,6 +126,7 @@
 		mips_cputype = CPU_R8000;
 		break;
 	case PRID_IMP_R10000:
+	case PRID_IMP_R12000:
 		mips_cputype = CPU_R10000;
 		break;
 	default:
@@ -146,14 +136,6 @@
 
 void __init setup_arch(char **cmdline_p)
 {
-#ifdef CONFIG_BLK_DEV_INITRD
-	unsigned long tmp;
-	unsigned long *initrd_header;
-#endif
-	int i;
-	pmd_t *pmd = kpmdtbl;
-	pte_t *pte = kptbl;
-
 	cpu_probe();
 	load_mmu();
 
@@ -164,37 +146,15 @@
 	ip27_setup();
 #endif
 
-	strncpy (command_line, arcs_cmdline, CL_SIZE);
+#ifdef CONFIG_ARC_MEMORY
+	bootmem_init ();
+#endif
+
+	strncpy(command_line, arcs_cmdline, CL_SIZE);
 	memcpy(saved_command_line, command_line, CL_SIZE);
 	saved_command_line[CL_SIZE-1] = '\0';
 
 	*cmdline_p = command_line;
 
-#ifdef CONFIG_BLK_DEV_INITRD
-#error "Initrd is broken, please fit it."
-	tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8;
-	if (tmp < (unsigned long)&_end)
-		tmp += PAGE_SIZE;
-	initrd_header = (unsigned long *)tmp;
-	if (initrd_header[0] == 0x494E5244) {
-		initrd_start = (unsigned long)&initrd_header[2];
-		initrd_end = initrd_start + initrd_header[1];
-		initrd_below_start_ok = 1;
-		if (initrd_end > memory_end) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-			       initrd_end,memory_end);
-			initrd_start = 0;
-		} else
-			*memory_start_p = initrd_end;
-	}
-#endif
-
 	paging_init();
-
-	memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER);
-	memset((void *)kpmdtbl, 0, PAGE_SIZE);
-	pgd_set(swapper_pg_dir, kpmdtbl);
-	for (i = 0; i < (1 << KPTBL_PAGE_ORDER); pmd++,i++,pte+=PTRS_PER_PTE)
-		pmd_val(*pmd) = (unsigned long)pte;
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c
--- v2.4.6/linux/arch/mips64/kernel/smp.c	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/kernel/smp.c	Wed Jul  4 11:50:39 2001
@@ -12,6 +12,7 @@
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/mmu_context.h>
+#include <asm/irq.h>
 
 #ifdef CONFIG_SGI_IP27
 
@@ -24,8 +25,6 @@
 #define DORESCHED	0xab
 #define DOCALL		0xbc
 
-#define IRQ_TO_SWLEVEL(i)	i + 7	/* Delete this from here */
-
 static void sendintr(int destid, unsigned char status)
 {
 	int irq;
@@ -44,7 +43,7 @@
 	 * with the CPU we want to send the interrupt to.
 	 */
 	REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
-			IRQ_TO_SWLEVEL(irq));
+			FAST_IRQ_TO_LEVEL(irq));
 #else
 	<< Bomb!  Must redefine this for more than 2 CPUS. >>
 #endif
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/traps.c linux/arch/mips64/kernel/traps.c
--- v2.4.6/linux/arch/mips64/kernel/traps.c	Sun Dec  3 17:48:19 2000
+++ linux/arch/mips64/kernel/traps.c	Wed Jul  4 11:50:39 2001
@@ -264,7 +264,7 @@
 
 	epc = (unsigned int *) (unsigned long) regs->cp0_epc;
 	if (regs->cp0_cause & CAUSEF_BD)
-		epc += 4;
+		epc++;
 
 	if (verify_area(VERIFY_READ, epc, 4)) {
 		force_sig(SIGSEGV, current);
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/unaligned.c linux/arch/mips64/kernel/unaligned.c
--- v2.4.6/linux/arch/mips64/kernel/unaligned.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/kernel/unaligned.c	Wed Jul  4 11:50:39 2001
@@ -82,6 +82,7 @@
 #include <asm/byteorder.h>
 #include <asm/inst.h>
 #include <asm/uaccess.h>
+#include <asm/system.h>
 
 #define STR(x)  __STR(x)
 #define __STR(x)  #x
@@ -364,12 +365,15 @@
 		return;
 	}
 
+	die_if_kernel ("Unhandled kernel unaligned access", regs);
 	send_sig(SIGSEGV, current, 1);
 	return;
 sigbus:
+	die_if_kernel ("Unhandled kernel unaligned access", regs);
 	send_sig(SIGBUS, current, 1);
 	return;
 sigill:
+	die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs);
 	send_sig(SIGILL, current, 1);
 	return;
 }
@@ -400,5 +404,6 @@
 	return;
 
 sigbus:
+	die_if_kernel ("Kernel unaligned instruction access", regs);
 	force_sig(SIGBUS, current);
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/memcpy.S linux/arch/mips64/lib/memcpy.S
--- v2.4.6/linux/arch/mips64/lib/memcpy.S	Tue Dec  5 23:15:12 2000
+++ linux/arch/mips64/lib/memcpy.S	Wed Jul  4 11:50:39 2001
@@ -238,8 +238,10 @@
 	 andi	ta2, a2, 0x40
 
 move_128bytes:
+#if (_MIPS_ISA == _MIPS_ISA_MIPS4)
 	pref	0, 2*128(a0)
 	pref	1, 2*128(a1)
+#endif
 	MOVE_BIGGERCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
 	MOVE_BIGGERCHUNK(a1, a0, 0x40, ta0, ta1, ta3, t0)
 	dsubu	t8, t8, 0x01
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/memset.S linux/arch/mips64/lib/memset.S
--- v2.4.6/linux/arch/mips64/lib/memset.S	Tue Dec  5 23:15:12 2000
+++ linux/arch/mips64/lib/memset.S	Wed Jul  4 11:50:39 2001
@@ -52,6 +52,7 @@
 1:
 
 FEXPORT(__bzero)
+	.type	__bzero, @function
 	sltiu	t0, a2, 8			/* very small region? */
 	bnez	t0, small_memset
 	 andi	t0, a0, 7			/* aligned? */
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/rtc-no.c linux/arch/mips64/lib/rtc-no.c
--- v2.4.6/linux/arch/mips64/lib/rtc-no.c	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/lib/rtc-no.c	Wed Jul  4 11:50:39 2001
@@ -9,7 +9,6 @@
  * Copyright (C) 1998, 2001 by Ralf Baechle
  */
 #include <linux/kernel.h>
-#include <linux/spinlock.h>
 #include <linux/mc146818rtc.h>
 
 static unsigned char no_rtc_read_data(unsigned long addr)
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/rtc-std.c linux/arch/mips64/lib/rtc-std.c
--- v2.4.6/linux/arch/mips64/lib/rtc-std.c	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/lib/rtc-std.c	Wed Jul  4 11:50:39 2001
@@ -7,7 +7,6 @@
  *
  * Copyright (C) 1998 by Ralf Baechle
  */
-#include <linux/spinlock.h>
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/watch.S linux/arch/mips64/lib/watch.S
--- v2.4.6/linux/arch/mips64/lib/watch.S	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/lib/watch.S	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: watch.S,v 1.1 1999/08/21 21:43:01 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -7,7 +6,7 @@
  * Kernel debug stuff to use the Watch registers.
  * Useful to find stack overflows, dangling pointers etc.
  *
- * Copyright (C) 1995, 1996, 1999 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1999, 2001 by Ralf Baechle
  */
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
@@ -15,23 +14,21 @@
 
 		.set	noreorder
 /*
- * Parameter: a0 - logic address to watch
- *                 Currently only KSEG0 addresses are allowed!
+ * Parameter: a0 - physical address to watch
  *            a1 - set bit #1 to trap on load references
  *                     bit #0 to trap on store references
  * Results  : none
  */
 		LEAF(__watch_set)
-		li	t0,0x80000000
-		subu	a0,t0
-		ori	a0,7
-		xori	a0,7
-		or	a0,a1
-		mtc0	a0,CP0_WATCHLO
-		sw	a0,watch_savelo
+		ori	a0, 7
+		xori	a0, 7
+		or	a0, a1
+		mtc0	a0, CP0_WATCHLO
+		sd	a0, watch_savelo
+		dsrl32	a0, a0, 0
 
 		jr	ra
-		 mtc0	zero,CP0_WATCHHI
+		 mtc0	zero, CP0_WATCHHI
 		END(__watch_set)
 
 /*
@@ -40,7 +37,7 @@
  */
 		LEAF(__watch_clear)
 		jr	ra
-		 mtc0	zero,CP0_WATCHLO
+		 mtc0	zero, CP0_WATCHLO
 		END(__watch_clear)
 
 /*
@@ -48,14 +45,13 @@
  * Results  : none
  */
 		LEAF(__watch_reenable)
-		lw	t0,watch_savelo
+		ld	t0, watch_savelo
 		jr	ra
-		 mtc0	t0,CP0_WATCHLO
+		 mtc0	t0, CP0_WATCHLO
 		END(__watch_reenable)
 
 /*
  * Saved value of the c0_watchlo register for watch_reenable()
  */
-		.data
-watch_savelo:	.word	0
-		.text
+		.local	watch_savelo
+		.comm	watch_savelo, 8, 8
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/andes.c linux/arch/mips64/mm/andes.c
--- v2.4.6/linux/arch/mips64/mm/andes.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/mm/andes.c	Wed Jul  4 11:50:39 2001
@@ -284,8 +284,8 @@
 
 	if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) ||
 	   (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) {
-		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d 
-			tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(), 
+		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d "
+			"tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(),
 			vma->vm_mm) & 0xff), pid);
 	}
 
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/extable.c linux/arch/mips64/mm/extable.c
--- v2.4.6/linux/arch/mips64/mm/extable.c	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/mm/extable.c	Wed Jul  4 11:50:39 2001
@@ -9,6 +9,7 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 extern const struct exception_table_entry __start___ex_table[];
@@ -35,26 +36,32 @@
 	return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
-
+	unsigned long ret = 0;
+	unsigned long flags;
+	
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return ret;
+	return ret;
 #else
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
 		if (mp->ex_table_start == NULL)
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
-		if (ret) return ret;
+		if (ret)
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c
--- v2.4.6/linux/arch/mips64/mm/fault.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/mips64/mm/fault.c	Wed Jul  4 11:50:39 2001
@@ -6,6 +6,7 @@
  * Copyright (C) 1995 - 2000 by Ralf Baechle
  * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
  */
+#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -31,6 +32,7 @@
 #define development_version (LINUX_VERSION_CODE & 0x100)
 
 extern void die(char *, struct pt_regs *, unsigned long write);
+extern int console_loglevel;
 
 /*
  * Macro for exception fixup code to access integer registers.
@@ -57,17 +59,34 @@
 	printk("Got exception 0x%lx at 0x%lx\n", retaddr, regs.cp0_epc);
 }
 
-extern spinlock_t console_lock, timerlist_lock;
+extern spinlock_t timerlist_lock;
 
 /*
  * Unlock any spinlocks which will prevent us from getting the
- * message out (timerlist_lock is acquired through the
+ * message out (timerlist_lock is aquired through the
  * console unblank code)
  */
-void bust_spinlocks(void)
+void bust_spinlocks(int yes)
 {
-	spin_lock_init(&console_lock);
 	spin_lock_init(&timerlist_lock);
+	if (yes) {
+		oops_in_progress = 1;
+#ifdef CONFIG_SMP
+		global_irq_lock = 0;	/* Many serial drivers do __global_cli() */
+#endif
+	} else {
+		int loglevel_save = console_loglevel;
+		unblank_screen();
+		oops_in_progress = 0;
+		/*
+		 * OK, the message is on the console.  Now we call printk()
+		 * without oops_in_progress set so that printk will give klogd
+		 * a poke.  Hold onto your hats...
+		 */
+		console_loglevel = 15;		/* NMI oopser may have shut the console up */
+		printk(" ");
+		console_loglevel = loglevel_save;
+	}
 }
 
 /*
@@ -84,6 +103,18 @@
 	unsigned long fixup;
 	siginfo_t info;
 
+	/*
+	 * We fault-in kernel-space virtual memory on-demand. The
+	 * 'reference' page table is init_mm.pgd.
+	 *
+	 * NOTE! We MUST NOT take any locks for this case. We may
+	 * be in an interrupt or a critical region, and should
+	 * only copy the information from the master page table,
+	 * nothing more.
+	 */
+	if (address >= TASK_SIZE)
+		goto vmalloc_fault;
+
 	info.si_code = SEGV_MAPERR;
 	/*
 	 * If we're in an interrupt or have no user
@@ -148,13 +179,7 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
-	/*
-	 * Quickly check for vmalloc range faults.
-	 */
-	if ((!vma) && (address >= VMALLOC_START) && (address < VMALLOC_END)) {
-		printk("Fix vmalloc invalidate fault\n");
-		while(1);
-	}
+bad_area_nosemaphore:
 	if (user_mode(regs)) {
 		tsk->thread.cp0_badvaddr = address;
 		tsk->thread.error_code = write;
@@ -195,7 +220,7 @@
 	 * terminate things with extreme prejudice.
 	 */
 
-	bust_spinlocks();
+	bust_spinlocks(1);
 
 	printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at "
 	       "address %08lx, epc == %08x, ra == %08x\n",
@@ -203,6 +228,7 @@
                (unsigned int) regs->regs[31]);
 	die("Oops", regs, write);
 	do_exit(SIGKILL);
+	bust_spinlocks(0);
 
 /*
  * We ran out of memory, or some other thing happened to us that made
@@ -232,4 +258,9 @@
 	/* Kernel mode? Handle exceptions or die */
 	if (!user_mode(regs))
 		goto no_context;
+
+	return;
+
+vmalloc_fault:
+	panic("Pagefault for kernel virtual memory");
 }
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/init.c linux/arch/mips64/mm/init.c
--- v2.4.6/linux/arch/mips64/mm/init.c	Mon Oct 16 12:58:51 2000
+++ linux/arch/mips64/mm/init.c	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: init.c,v 1.13 2000/02/23 00:41:00 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -37,27 +36,11 @@
 #include <asm/sgialib.h>
 #endif
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 
-unsigned long totalram_pages;
-
-void __bad_pte_kernel(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, BAD_PAGETABLE);
-}
-
-void __bad_pte(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, BAD_PAGETABLE);
-}
+mmu_gather_t mmu_gathers[NR_CPUS];
 
-/* Fixme, we need something like BAD_PMDTABLE ...  */
-void __bad_pmd(pgd_t *pgd)
-{
-	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-	pgd_set(pgd, empty_bad_pmd_table);
-}
+unsigned long totalram_pages;
 
 void pgd_init(unsigned long page)
 {
@@ -113,72 +96,6 @@
 	}
 }
 
-pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
-{
-	pmd_t *pmd;
-
-	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1);
-	if (pgd_none(*pgd)) {
-		if (pmd) {
-			pmd_init((unsigned long)pmd, (unsigned long)invalid_pte_table);
-			pgd_set(pgd, pmd);
-			return pmd + offset;
-		}
-		pgd_set(pgd, BAD_PMDTABLE);
-		return NULL;
-	}
-	free_page((unsigned long)pmd);
-	if (pgd_bad(*pgd)) {
-		__bad_pmd(pgd);
-		return NULL;
-	}
-	return (pmd_t *) pgd_page(*pgd) + offset;
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *page;
-
-	page = (pte_t *) __get_free_pages(GFP_USER, 1);
-	if (pmd_none(*pmd)) {
-		if (page) {
-			clear_page(page);
-			pmd_set(pmd, page);
-			return page + offset;
-		}
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)page);
-	if (pmd_bad(*pmd)) {
-		__bad_pte_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *page;
-
-	page = (pte_t *) __get_free_pages(GFP_KERNEL, 0);
-	if (pmd_none(*pmd)) {
-		if (page) {
-			clear_page(page);
-			pmd_val(*pmd) = (unsigned long)page;
-			return page + offset;
-		}
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_pages((unsigned long)page, 0);
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
@@ -205,7 +122,7 @@
 }
 
 /*
- * We have upto 8 empty zeroed pages so we can map one of the right colour
+ * We have up to 8 empty zeroed pages so we can map one of the right colour
  * when needed.  This is necessary only on R4000 / R4400 SC and MC versions
  * where we have to avoid VCED / VECI exceptions for good performance at
  * any price.  Since page is never written to after the initialization we
@@ -247,32 +164,155 @@
 	return 1UL << order;
 }
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-pmd_t * __bad_pmd_table(void)
+void __init add_memory_region(unsigned long start, unsigned long size,
+                              long type)
 {
-	return empty_bad_pmd_table;
-}
+        int x = boot_mem_map.nr_map;
 
-pte_t * __bad_pagetable(void)
-{
-	return empty_bad_page_table;
+        if (x == BOOT_MEM_MAP_MAX) {
+                printk("Ooops! Too many entries in the memory map!\n");
+                return;
+        }
+
+        boot_mem_map.map[x].addr = start;
+        boot_mem_map.map[x].size = size;
+        boot_mem_map.map[x].type = type;
+        boot_mem_map.nr_map++;
+}
+
+static void __init print_memory_map(void)
+{
+        int i;
+
+        for (i = 0; i < boot_mem_map.nr_map; i++) {
+                printk(" memory: %08lx @ %08lx ",
+                        boot_mem_map.map[i].size, boot_mem_map.map[i].addr);
+                switch (boot_mem_map.map[i].type) {
+                case BOOT_MEM_RAM:
+                        printk("(usable)\n");
+                        break;
+                case BOOT_MEM_ROM_DATA:
+                        printk("(ROM data)\n");
+                        break;
+                case BOOT_MEM_RESERVED:
+                        printk("(reserved)\n");
+                        break;
+                default:
+                        printk("type %lu\n", boot_mem_map.map[i].type);
+                        break;
+                }
+        }
 }
 
-pte_t __bad_page(void)
-{
-	return __pte(0);
+void bootmem_init(void) {
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned long tmp;
+	unsigned long *initrd_header;
+#endif
+	unsigned long bootmap_size;
+	unsigned long start_pfn, max_pfn;
+	int i;
+	extern int _end;
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+	/*
+	 * Partially used pages are not usable - thus
+	 * we are rounding upwards.
+	 */
+	start_pfn = PFN_UP(__pa(&_end));
+
+	/* Find the highest page frame number we have available.  */
+	max_pfn = 0;
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long start, end;
+
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			continue;
+
+		start = PFN_UP(boot_mem_map.map[i].addr);
+		end = PFN_DOWN(boot_mem_map.map[i].addr
+		      + boot_mem_map.map[i].size);
+
+		if (start >= end)
+			continue;
+		if (end > max_pfn)
+			max_pfn = end;
+	}
+
+	/* Initialize the boot-time allocator.  */
+	bootmap_size = init_bootmem(start_pfn, max_pfn);
+
+	/*
+	 * Register fully available low RAM pages with the bootmem allocator.
+	 */
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long curr_pfn, last_pfn, size;
+
+		/*
+		 * Reserve usable memory.
+		 */
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			continue;
+
+		/*
+		 * We are rounding up the start address of usable memory:
+		 */
+		curr_pfn = PFN_UP(boot_mem_map.map[i].addr);
+		if (curr_pfn >= max_pfn)
+			continue;
+		if (curr_pfn < start_pfn)
+			curr_pfn = start_pfn;
+
+		/*
+		 * ... and at the end of the usable range downwards:
+		 */
+		last_pfn = PFN_DOWN(boot_mem_map.map[i].addr
+				    + boot_mem_map.map[i].size);
+
+		if (last_pfn > max_pfn)
+			last_pfn = max_pfn;
+
+		/*
+		 * ... finally, did all the rounding and playing
+		 * around just make the area go away?
+		 */
+		if (last_pfn <= curr_pfn)
+			continue;
+
+		size = last_pfn - curr_pfn;
+		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
+	}
+
+	/* Reserve the bootmap memory.  */
+	reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+#error "Initrd is broken, please fit it."
+	tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8;
+	if (tmp < (unsigned long)&_end)
+		tmp += PAGE_SIZE;
+	initrd_header = (unsigned long *)tmp;
+	if (initrd_header[0] == 0x494E5244) {
+		initrd_start = (unsigned long)&initrd_header[2];
+		initrd_end = initrd_start + initrd_header[1];
+		initrd_below_start_ok = 1;
+		if (initrd_end > memory_end) {
+			printk("initrd extends beyond end of memory "
+			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			       initrd_end,memory_end);
+			initrd_start = 0;
+		} else
+			*memory_start_p = initrd_end;
+	}
+#endif
+
+#undef PFN_UP
+#undef PFN_DOWN
+#undef PFN_PHYS
+
 }
 
 void show_mem(void)
@@ -312,27 +352,39 @@
 
 void __init paging_init(void)
 {
+	pmd_t *pmd = kpmdtbl;
+	pte_t *pte = kptbl;
+
 	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
 	unsigned long max_dma, low;
+	int i;
 
 	/* Initialize the entire pgd.  */
 	pgd_init((unsigned long)swapper_pg_dir);
 	pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
 	memset((void *)invalid_pte_table, 0, sizeof(pte_t) * PTRS_PER_PTE);
-	pmd_init((unsigned long)empty_bad_pmd_table, (unsigned long)empty_bad_page_table);
-	memset((void *)empty_bad_page_table, 0, sizeof(pte_t) * PTRS_PER_PTE);
 
 	max_dma =  virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 	low = max_low_pfn;
 
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
 	if (low < max_dma)
 		zones_size[ZONE_DMA] = low;
 	else {
 		zones_size[ZONE_DMA] = max_dma;
 		zones_size[ZONE_NORMAL] = low - max_dma;
 	}
+#else
+	zones_size[ZONE_DMA] = low;
+#endif
 
 	free_area_init(zones_size);
+	
+	memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER);
+	memset((void *)kpmdtbl, 0, PAGE_SIZE);
+	pgd_set(swapper_pg_dir, kpmdtbl);
+	for (i = 0; i < (1 << KPTBL_PAGE_ORDER); pmd++,i++,pte+=PTRS_PER_PTE)
+		pmd_val(*pmd) = (unsigned long)pte;
 }
 
 extern int page_is_ram(unsigned long pagenr);
@@ -411,7 +463,7 @@
 si_meminfo(struct sysinfo *val)
 {
 	val->totalram = totalram_pages;
-	val->sharedram = 0;
+	val->sharedram = atomic_read(&shmem_nrpages);
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
 	val->totalhigh = 0;
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/r4xx0.c linux/arch/mips64/mm/r4xx0.c
--- v2.4.6/linux/arch/mips64/mm/r4xx0.c	Sun Feb  4 21:48:46 2001
+++ linux/arch/mips64/mm/r4xx0.c	Wed Jul  4 11:50:39 2001
@@ -6,7 +6,7 @@
  * r4xx0.c: R4000 processor variant specific MMU/Cache routines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <linux/init.h>
@@ -377,7 +377,7 @@
 		"ld\t%3,-8(%1)\n\t"
 		"sd\t%2,-16(%0)\n\t"
 		"bne\t$1,%0,1b\n\t"
-		" sd\t%4,-8(%0)\n\t"
+		" sd\t%3,-8(%0)\n\t"
 		".set\tat\n\t"
 		".set\treorder"
 		:"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2)
@@ -1017,7 +1017,7 @@
 	struct vm_area_struct *vma;
 	unsigned long flags;
 
-	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
+	if (CPU_CONTEXT(smp_processor_id(), mm) != 0)
 		return;
 
 	start &= PAGE_MASK;
@@ -1747,15 +1747,15 @@
 	unsigned long end, a;
 	unsigned int flags;
 
-	if (size >= dcache_size) {
+	if (size >= (unsigned long)dcache_size) {
 		flush_cache_l1();
 	} else {
 		/* Workaround for R4600 bug.  See comment above. */
 		__save_and_cli(flags);
 		*(volatile unsigned long *)KSEG1;
 
-		a = addr & ~(dc_lsize - 1);
-		end = (addr + size) & ~(dc_lsize - 1);
+		a = addr & ~((unsigned long)dc_lsize - 1);
+		end = (addr + size) & ~((unsigned long)dc_lsize - 1);
 		while (1) {
 			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
 			if (a == end) break;
@@ -1771,13 +1771,13 @@
 {
 	unsigned long end, a;
 
-	if (size >= scache_size) {
+	if (size >= (unsigned long)scache_size) {
 		flush_cache_l1();
 		return;
 	}
 
-	a = addr & ~(sc_lsize - 1);
-	end = (addr + size) & ~(sc_lsize - 1);
+	a = addr & ~((unsigned long)sc_lsize - 1);
+	end = (addr + size) & ~((unsigned long)sc_lsize - 1);
 	while (1) {
 		flush_scache_line(a);	/* Hit_Writeback_Inv_SD */
 		if (a == end) break;
@@ -1791,15 +1791,15 @@
 	unsigned long end, a;
 	unsigned int flags;
 
-	if (size >= dcache_size) {
+	if (size >= (unsigned long)dcache_size) {
 		flush_cache_l1();
 	} else {
 		/* Workaround for R4600 bug.  See comment above. */
 		__save_and_cli(flags);
 		*(volatile unsigned long *)KSEG1;
 
-		a = addr & ~(dc_lsize - 1);
-		end = (addr + size) & ~(dc_lsize - 1);
+		a = addr & ~((unsigned long)dc_lsize - 1);
+		end = (addr + size) & ~((unsigned long)dc_lsize - 1);
 		while (1) {
 			flush_dcache_line(a); /* Hit_Writeback_Inv_D */
 			if (a == end) break;
@@ -1816,13 +1816,13 @@
 {
 	unsigned long end, a;
 
-	if (size >= scache_size) {
+	if (size >= (unsigned long)scache_size) {
 		flush_cache_l1();
 		return;
 	}
 
-	a = addr & ~(sc_lsize - 1);
-	end = (addr + size) & ~(sc_lsize - 1);
+	a = addr & ~((unsigned long)sc_lsize - 1);
+	end = (addr + size) & ~((unsigned long)sc_lsize - 1);
 	while (1) {
 		flush_scache_line(a); /* Hit_Writeback_Inv_SD */
 		if (a == end) break;
@@ -1845,11 +1845,11 @@
 {
 	unsigned long daddr, iaddr;
 
-	daddr = addr & ~(dc_lsize - 1);
+	daddr = addr & ~((unsigned long)dc_lsize - 1);
 	__asm__ __volatile__("nop;nop;nop;nop");	/* R4600 V1.7 */
 	protected_writeback_dcache_line(daddr);
 	protected_writeback_dcache_line(daddr + dc_lsize);
-	iaddr = addr & ~(ic_lsize - 1);
+	iaddr = addr & ~((unsigned long)ic_lsize - 1);
 	protected_flush_icache_line(iaddr);
 	protected_flush_icache_line(iaddr + ic_lsize);
 }
@@ -1859,7 +1859,7 @@
 	unsigned long daddr, iaddr;
 	unsigned int flags;
 
-	daddr = addr & ~(dc_lsize - 1);
+	daddr = addr & ~((unsigned long)dc_lsize - 1);
 	__save_and_cli(flags);
 
 	/* Clear internal cache refill buffer */
@@ -1867,7 +1867,7 @@
 
 	protected_writeback_dcache_line(daddr);
 	protected_writeback_dcache_line(daddr + dc_lsize);
-	iaddr = addr & ~(ic_lsize - 1);
+	iaddr = addr & ~((unsigned long)ic_lsize - 1);
 	protected_flush_icache_line(iaddr);
 	protected_flush_icache_line(iaddr + ic_lsize);
 	__restore_flags(flags);
@@ -2384,7 +2384,11 @@
 
 	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
 
+#ifdef CONFIG_MIPS_UNCACHED
+	set_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+#else
 	set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
+#endif /* UNCACHED */
 
 	probe_icache(config);
 	probe_dcache(config);
diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c
--- v2.4.6/linux/arch/mips64/mm/umap.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/mips64/mm/umap.c	Wed Jul  4 11:50:39 2001
@@ -1,11 +1,11 @@
-/* $Id: umap.c,v 1.4 2000/01/29 01:41:59 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Copyright (C) 1994 Linus Torvalds
  * Copyright (C) 1997 Miguel de Icaza
+ * Copyright (C) 2001 Ralf Baechle
  */
 #include <linux/stat.h>
 #include <linux/sched.h>
@@ -16,6 +16,7 @@
 #include <linux/shm.h>
 #include <linux/errno.h>
 #include <linux/mman.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
@@ -101,9 +102,12 @@
 	up_write (&task->mm->mmap_sem);
 }
 
+EXPORT_SYMBOL(remove_mapping);
+
 void *vmalloc_uncached (unsigned long size)
 {
-	return vmalloc_prot (size, PAGE_KERNEL_UNCACHED);
+	return __vmalloc (size, GFP_KERNEL | __GFP_HIGHMEM,
+				PAGE_KERNEL_UNCACHED);
 }
 
 static inline void free_pte(pte_t page)
diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.4.6/linux/arch/ppc/kernel/pmac_pci.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/pmac_pci.c	Wed Jul  4 11:50:39 2001
@@ -249,7 +249,7 @@
 	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
 	udelay(2);
 	vendev = in_le32((volatile unsigned int *)bp->cfg_data);
-	if (vendev == (PCI_VENDOR_ID_APPLE_BANDIT << 16) + 
+	if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + 
 			PCI_VENDOR_ID_APPLE) {
 		/* read the revision id */
 		out_le32(bp->cfg_addr,
diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.4.6/linux/arch/ppc/kernel/prom.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/prom.c	Sun Jul  8 13:17:30 2001
@@ -116,8 +116,11 @@
 unsigned int rtas_size;
 unsigned int old_rtas;
 
-/* Set for a newworld machine */
+/* Set for a newworld or CHRP machine */
 int use_of_interrupt_tree;
+struct device_node *dflt_interrupt_controller;
+int num_interrupt_controllers;
+
 int pmac_newworld;
 
 static struct device_node *allnodes;
@@ -1153,7 +1156,19 @@
 		*prev_propp = PTRUNRELOC(pp);
 		prev_propp = &pp->next;
 	}
-	*prev_propp = 0;
+	if (np->node != NULL) {
+		/* Add a "linux,phandle" property" */
+		pp = (struct property *) mem_start;
+		*prev_propp = PTRUNRELOC(pp);
+		prev_propp = &pp->next;
+		namep = (char *) (pp + 1);
+		pp->name = PTRUNRELOC(namep);
+		strcpy(namep, RELOC("linux,phandle"));
+		mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
+		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
+		pp->length = sizeof(np->node);
+	}
+	*prev_propp = NULL;
 
 	/* get the node's full name */
 	l = (int) call_prom(RELOC("package-to-path"), 3, 1, node,
@@ -1186,19 +1201,46 @@
 finish_device_tree(void)
 {
 	unsigned long mem = (unsigned long) klimit;
+	struct device_node *np;
 
-	/* All newworld machines now use the interrupt tree */
-	struct device_node *np = allnodes;
-
-	while(np && (_machine == _MACH_Pmac)) {
+	/* All newworld pmac machines and CHRPs now use the interrupt tree */
+	for (np = allnodes; np != NULL; np = np->allnext) {
 		if (get_property(np, "interrupt-parent", 0)) {
-			pmac_newworld = 1;
+			use_of_interrupt_tree = 1;
 			break;
 		}
-		np = np->allnext;
 	}
-	if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
-		use_of_interrupt_tree = 1;
+	if (_machine == _MACH_Pmac && use_of_interrupt_tree)
+		pmac_newworld = 1;
+
+#ifdef CONFIG_BOOTX_TEXT
+	if (boot_infos && pmac_newworld) {
+		prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
+		prom_print("          You should use an Open Firmware bootloader\n");
+	}
+#endif /* CONFIG_BOOTX_TEXT */
+
+	if (use_of_interrupt_tree) {
+		/*
+		 * We want to find out here how many interrupt-controller
+		 * nodes there are, and if we are booted from BootX,
+		 * we need a pointer to the first (and hopefully only)
+		 * such node.  But we can't use find_devices here since
+		 * np->name has not been set yet.  -- paulus
+		 */
+		int n = 0;
+		char *name;
+
+		for (np = allnodes; np != NULL; np = np->allnext) {
+			if ((name = get_property(np, "name", NULL)) == NULL
+			    || strcmp(name, "interrupt-controller") != 0)
+				continue;
+			if (n == 0)
+				dflt_interrupt_controller = np;
+			++n;
+		}
+		num_interrupt_controllers = n;
+	}
 
 	mem = finish_node(allnodes, mem, NULL, 1, 1);
 	dev_tree_size = mem - (unsigned long) allnodes;
@@ -1240,9 +1282,8 @@
 	if (ifunc != NULL) {
 		mem_start = ifunc(np, mem_start, naddrc, nsizec);
 	}
-	if (use_of_interrupt_tree) {
+	if (use_of_interrupt_tree)
 		mem_start = finish_node_interrupts(np, mem_start);
-	}
 
 	/* Look for #address-cells and #size-cells properties. */
 	ip = (int *) get_property(np, "#address-cells", 0);
@@ -1298,141 +1339,210 @@
 	return mem_start;
 }
 
-/* This routine walks the interrupt tree for a given device node and gather 
- * all necessary informations according to the draft interrupt mapping
- * for CHRP. The current version was only tested on Apple "Core99" machines
- * and may not handle cascaded controllers correctly.
+/*
+ * Find the interrupt parent of a node.
+ */
+static struct device_node *intr_parent(struct device_node *p)
+{
+	phandle *parp;
+
+	parp = (phandle *) get_property(p, "interrupt-parent", NULL);
+	if (parp == NULL)
+		return p->parent;
+	p = find_phandle(*parp);
+	if (p != NULL)
+		return p;
+	/*
+	 * On a powermac booted with BootX, we don't get to know the
+	 * phandles for any nodes, so find_phandle will return NULL.
+	 * Fortunately these machines only have one interrupt controller
+	 * so there isn't in fact any ambiguity.  -- paulus
+	 */
+	if (num_interrupt_controllers == 1)
+		p = dflt_interrupt_controller;
+	return p;
+}
+
+/*
+ * Find out the size of each entry of the interrupts property
+ * for a node.
  */
-__init
-static unsigned long
-finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+static int
+prom_n_intr_cells(struct device_node *np)
 {
-	/* Finish this node */
-	unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
-	phandle *parent;
-	struct device_node *node, *parent_node;
-	int l, isize, ipsize, asize, map_size, regpsize;
-
-	/* Currently, we don't look at all nodes with no "interrupts" property */
-	interrupts = (unsigned int *)get_property(np, "interrupts", &l);
-	if (interrupts == NULL)
-		return mem_start;
-	ipsize = l>>2;
+	struct device_node *p;
+	unsigned int *icp;
 
-	reg = (unsigned int *)get_property(np, "reg", &l);
-	regpsize = l>>2;
+	for (p = np; (p = intr_parent(p)) != NULL; ) {
+		icp = (unsigned int *)
+			get_property(p, "#interrupt-cells", NULL);
+		if (icp != NULL)
+			return *icp;
+		if (get_property(p, "interrupt-controller", NULL) != NULL
+		    || get_property(p, "interrupt-map", NULL) != NULL) {
+			printk("oops, node %s doesn't have #interrupt-cells\n",
+			       p->full_name);
+			return 1;
+		}
+	}
+	printk("prom_n_intr_cells failed for %s\n", np->full_name);
+	return 1;
+}
 
-	/* We assume default interrupt cell size is 1 (bugus ?) */
-	isize = 1;
-	node = np;
-	
-	do {
-	    /* We adjust the cell size if the current parent contains an #interrupt-cells
-	     * property */
-	    isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
-	    if (isizep)
-	    	isize = *isizep;
-
-	    /* We don't do interrupt cascade (ISA) for now, we stop on the first 
-	     * controller found
-	     */
-	    if (get_property(node, "interrupt-controller", &l)) {
-	    	int i,j;
-		int cvt_irq;
-
-		/* XXX on chrp, offset interrupt numbers for the
-		   8259 by 0, those for the openpic by 16 */
-		cvt_irq = _machine == _MACH_chrp
-			&& get_property(node, "interrupt-parent", NULL) == 0;
-	    	np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = ipsize / isize;
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-		    np->intrs[i].line = *interrupts++;
-		    if (cvt_irq)
-			np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
-		    np->intrs[i].sense = 1;
-		    if (isize > 1)
-		        np->intrs[i].sense = *interrupts++;
-		    for (j=2; j<isize; j++)
-		    	interrupts++;
+/*
+ * Map an interrupt from a device up to the platform interrupt
+ * descriptor.
+ */
+static int
+map_interrupt(unsigned int **irq, struct device_node **ictrler,
+	      struct device_node *np, unsigned int *ints, int nintrc)
+{
+	struct device_node *p, *ipar;
+	unsigned int *imap, *imask, *ip;
+	int i, imaplen, match;
+	int newintrc, newaddrc;
+	unsigned int *reg;
+	int naddrc;
+
+	reg = (unsigned int *) get_property(np, "reg", NULL);
+	naddrc = prom_n_addr_cells(np);
+	p = intr_parent(np);
+	while (p != NULL) {
+		if (get_property(p, "interrupt-controller", NULL) != NULL)
+			/* this node is an interrupt controller, stop here */
+			break;
+		imap = (unsigned int *)
+			get_property(p, "interrupt-map", &imaplen);
+		if (imap == NULL) {
+			p = intr_parent(p);
+			continue;
 		}
+		imask = (unsigned int *)
+			get_property(p, "interrupt-map-mask", NULL);
+		if (imask == NULL) {
+			printk("oops, %s has interrupt-map but no mask\n",
+			       p->full_name);
+			return 0;
+		}
+		imaplen /= sizeof(unsigned int);
+		match = 0;
+		ipar = NULL;
+		while (imaplen > 0 && !match) {
+			/* check the child-interrupt field */
+			match = 1;
+			for (i = 0; i < naddrc && match; ++i)
+				match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
+			for (; i < naddrc + nintrc && match; ++i)
+				match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
+			imap += naddrc + nintrc;
+			imaplen -= naddrc + nintrc;
+			/* grab the interrupt parent */
+			ipar = find_phandle((phandle) *imap++);
+			--imaplen;
+			if (ipar == NULL && num_interrupt_controllers == 1)
+				/* cope with BootX not giving us phandles */
+				ipar = dflt_interrupt_controller;
+			if (ipar == NULL) {
+				printk("oops, no int parent %x in map of %s\n",
+				       imap[-1], p->full_name);
+				return 0;
+			}
+			/* find the parent's # addr and intr cells */
+			ip = (unsigned int *)
+				get_property(ipar, "#interrupt-cells", NULL);
+			if (ip == NULL) {
+				printk("oops, no #interrupt-cells on %s\n",
+				       ipar->full_name);
+				return 0;
+			}
+			newintrc = *ip;
+			ip = (unsigned int *)
+				get_property(ipar, "#address-cells", NULL);
+			newaddrc = (ip == NULL)? 0: *ip;
+			imap += newaddrc + newintrc;
+			imaplen -= newaddrc + newintrc;
+		}
+		if (imaplen < 0) {
+			printk("oops, error decoding int-map on %s, len=%d\n",
+			       p->full_name, imaplen);
+			return 0;
+		}
+		if (!match) {
+			printk("oops, no match in %s int-map for %s\n",
+			       p->full_name, np->full_name);
+			return 0;
+		}
+		p = ipar;
+		naddrc = newaddrc;
+		nintrc = newintrc;
+		ints = imap - nintrc;
+		reg = ints - naddrc;
+	}
+	if (p == NULL)
+		printk("hmmm, int tree for %s doesn't have ctrler\n",
+		       np->full_name);
+	*irq = ints;
+	*ictrler = p;
+	return nintrc;
+}
+
+/*
+ * New version of finish_node_interrupts.
+ */
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+	unsigned int *ints;
+	int intlen, intrcells;
+	int i, j, n, offset;
+	unsigned int *irq;
+	struct device_node *ic;
+
+	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+	if (ints == NULL)
 		return mem_start;
-	    }
-	    /* We lookup for an interrupt-map. This code can only handle one interrupt
-	     * per device in the map. We also don't handle #address-cells in the parent
-	     * I skip the pci node itself here, may not be necessary but I don't like it's
-	     * reg property.
-	     */
-	    if (np != node)
-	        map = (unsigned int *)get_property(node, "interrupt-map", &l);
-	     else
-	     	map = NULL;
-	    if (map && l) {
-	    	int i, found, temp_isize;
-	        map_size = l>>2;
-	        map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
-	        asizep = (unsigned int *)get_property(node, "#address-cells", &l);
-	        if (asizep && l == sizeof(unsigned int))
-	            asize = *asizep;
-	        else
-	            asize = 0;
-	        found = 0;
-	        while(map_size>0 && !found) {
-	            found = 1;
-	            for (i=0; i<asize; i++) {
-	            	unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
-	            	if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
-	           	    found = 0;
-	           	map++;
-	           	map_size--;
-	            }
-	            for (i=0; i<isize; i++) {
-	            	unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
-	            	if ((mask & *map) != (mask & interrupts[i]))
-	            	    found = 0;
-	            	map++;
-	            	map_size--;
-	            }
-	            parent = *((phandle *)(map));
-	            map+=1; map_size-=1;
-	            parent_node = find_phandle(parent);
-	            temp_isize = isize;
-	            if (parent_node) {
-			isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
-	    		if (isizep)
-	    		    temp_isize = *isizep;
-	            }
-	            if (!found) {
-	            	map += temp_isize;
-	            	map_size-=temp_isize;
-	            }
-	        }
-	        if (found) {
-	            node = parent_node;
-	            reg = NULL;
-	            regpsize = 0;
-	            interrupts = (unsigned int *)map;
-	            ipsize = temp_isize*1;
-		    continue;
-	        }
-	    }
-	    /* We look for an explicit interrupt-parent.
-	     */
-	    parent = (phandle *)get_property(node, "interrupt-parent", &l);
-	    if (parent && (l == sizeof(phandle)) &&
-	    	(parent_node = find_phandle(*parent))) {
-	    	node = parent_node;
-	    	continue;
-	    }
-	    /* Default, get real parent */
-	    node = node->parent;
-	} while(node);
+	intrcells = prom_n_intr_cells(np);
+	intlen /= intrcells * sizeof(unsigned int);
+	np->n_intrs = intlen;
+	np->intrs = (struct interrupt_info *) mem_start;
+	mem_start += intlen * sizeof(struct interrupt_info);
+
+	for (i = 0; i < intlen; ++i) {
+		np->intrs[i].line = 0;
+		np->intrs[i].sense = 1;
+		n = map_interrupt(&irq, &ic, np, ints, intrcells);
+		if (n <= 0)
+			continue;
+		offset = 0;
+		/*
+		 * On a CHRP we have an 8259 which is subordinate to
+		 * the openpic in the interrupt tree, but we want the
+		 * openpic's interrupt numbers offsetted, not the 8259's.
+		 * So we apply the offset if the controller is at the
+		 * root of the interrupt tree, i.e. has no interrupt-parent.
+		 * This doesn't cope with the general case of multiple
+		 * cascaded interrupt controllers, but then neither will
+		 * irq.c at the moment either.  -- paulus
+		 */
+		if (num_interrupt_controllers > 1 && ic != NULL
+		    && get_property(ic, "interrupt-parent", NULL) == NULL)
+			offset = 16;
+		np->intrs[i].line = irq[0] + offset;
+		if (n > 1)
+			np->intrs[i].sense = irq[1];
+		if (n > 2) {
+			printk("hmmm, got %d intr cells for %s:", n,
+			       np->full_name);
+			for (j = 0; j < n; ++j)
+				printk(" %d", irq[j]);
+			printk("\n");
+		}
+		ints += intrcells;
+	}
 
 	return mem_start;
 }
 
-
 /*
  * When BootX makes a copy of the device tree from the MacOS
  * Name Registry, it is in the format we use but all of the pointers
@@ -1475,7 +1585,7 @@
 		ip = (int *) get_property(np, "#address-cells", 0);
 		if (ip != NULL)
 			return *ip;
-	} while(np->parent);
+	} while (np->parent);
 	/* No #address-cells property for the root node, default to 1 */
 	return 1;
 }
@@ -1490,7 +1600,7 @@
 		ip = (int *) get_property(np, "#size-cells", 0);
 		if (ip != NULL)
 			return *ip;
-	} while(np->parent);
+	} while (np->parent);
 	/* No #size-cells property for the root node, default to 1 */
 	return 1;
 }
@@ -1502,8 +1612,7 @@
 {
 	struct address_range *adr;
 	struct pci_reg_property *pci_addrs;
-	int i, l, *ip, ml;
-	struct pci_intr_map *imp;
+	int i, l, *ip;
 
 	pci_addrs = (struct pci_reg_property *)
 		get_property(np, "assigned-addresses", &l);
@@ -1525,44 +1634,6 @@
 	if (use_of_interrupt_tree)
 		return mem_start;
 
-	/*
-	 * If the pci host bridge has an interrupt-map property,
-	 * look for our node in it.
-	 */
-	if (np->parent != 0 && pci_addrs != 0
-	    && (imp = (struct pci_intr_map *)
-		get_property(np->parent, "interrupt-map", &ml)) != 0
-	    && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
-		unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
-		unsigned int cell_size;
-		struct device_node* np2;
-		/* This is hackish, but is only used for BootX booting */
-		cell_size = sizeof(struct pci_intr_map);
-		np2 = np->parent;
-		while(np2) {
-			if (device_is_compatible(np2, "uni-north")) {
-				cell_size += 4;
-				break;
-			}
-			np2 = np2->parent;
-		}
-		np->n_intrs = 0;
-		np->intrs = (struct interrupt_info *) mem_start;
-		for (i = 0; (ml -= cell_size) >= 0; ++i) {
-			if (imp->addr.a_hi == devfn) {
-				np->intrs[np->n_intrs].line = imp->intr;
-				np->intrs[np->n_intrs].sense = 1; /* FIXME */
-				++np->n_intrs;
-			}
-			imp = (struct pci_intr_map *)(((unsigned int)imp)
-				+ cell_size);
-		}
-		if (np->n_intrs == 0)
-			np->intrs = 0;
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		return mem_start;
-	}
-
 	ip = (int *) get_property(np, "AAPL,interrupts", &l);
 	if (ip == 0 && np->parent)
 		ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
@@ -1677,26 +1748,10 @@
 		ip = (int *) get_property(np, "AAPL,interrupts", &l);
 	if (ip != 0) {
 		np->intrs = (struct interrupt_info *) mem_start;
-		if (_machine == _MACH_Pmac) {
-			/* for the iMac */
-			np->n_intrs = l / sizeof(int);
-			/* Hack for BootX on Core99 */
-			if (keylargo)
-				np->n_intrs = np->n_intrs/2;
-			for (i = 0; i < np->n_intrs; ++i) {
-				np->intrs[i].line = *ip++;
-				if (keylargo)
-					np->intrs[i].sense = *ip++;
-				else
-					np->intrs[i].sense = 1;
-			}
-		} else {
-			/* CHRP machines */
-			np->n_intrs = l / (2 * sizeof(int));
-			for (i = 0; i < np->n_intrs; ++i) {
-				np->intrs[i].line = openpic_to_irq(*ip++);
-				np->intrs[i].sense = *ip++;
-			}
+		np->n_intrs = l / sizeof(int);
+		for (i = 0; i < np->n_intrs; ++i) {
+			np->intrs[i].line = *ip++;
+			np->intrs[i].sense = 1;
 		}
 		mem_start += np->n_intrs * sizeof(struct interrupt_info);
 	}
@@ -1978,13 +2033,12 @@
 {
 	struct property *pp;
 
-	for (pp = np->properties; pp != 0; pp = pp->next) {
+	for (pp = np->properties; pp != 0; pp = pp->next)
 		if (pp->name != NULL && strcmp(pp->name, name) == 0) {
 			if (lenp != 0)
 				*lenp = pp->length;
 			return pp->value;
 		}
-	}
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- v2.4.6/linux/arch/s390/kernel/entry.S	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/kernel/entry.S	Wed Jul  4 11:50:39 2001
@@ -668,7 +668,7 @@
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         srl     %r3,2
         cl      %r3,BASED(.Lc4)   # protection-exception ?
-        bne     BASED(pgm_go)     # if not,
+        bne     BASED(pgm_per)    # if not,
         l       %r5,SP_PSW+4(15)  # load psw addr
         sr      %r5,%r7           # substract ilc from psw
         st      %r5,SP_PSW+4(15)  # store corrected psw addr
diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- v2.4.6/linux/arch/s390/kernel/head.S	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/kernel/head.S	Wed Jul  4 11:50:39 2001
@@ -262,8 +262,7 @@
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
         l     %r12,.Lparm                      # pointer to parameter area
-        st    %r1,__LC_IPLDEV                  # store ipl device number
-        st    %r1,IPL_DEVICE-PARMAREA(%r12)
+        st    %r1,IPL_DEVICE-PARMAREA(%r12)    # store ipl device number
 
 #
 # load parameter file from ipl device
@@ -463,7 +462,9 @@
 startup:basr  %r13,0                     # get base
 .LPG1:  lctl  %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
 	l     %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
-
+					 # move IPL device to lowcore
+        mvc   __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
+	
 #
 # find out memory size.
 #
diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c
--- v2.4.6/linux/arch/s390/kernel/irq.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/kernel/irq.c	Wed Jul  4 11:50:39 2001
@@ -386,8 +386,11 @@
         /* For now, nothing... */
 }
 
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+#endif
+
 EXPORT_SYMBOL(global_bh_lock);
diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/reipl.S linux/arch/s390/kernel/reipl.S
--- v2.4.6/linux/arch/s390/kernel/reipl.S	Tue Feb 13 14:13:43 2001
+++ linux/arch/s390/kernel/reipl.S	Wed Jul  4 11:50:39 2001
@@ -55,7 +55,7 @@
 .Ldispsw:	.long   0x000a0000,0x00000000
 .Liplccws:	.long   0x02000000,0x60000018
 		.long   0x08000008,0x20000001
-.Liplorb:	.long	0x0049504c,0x0000ff80
+.Liplorb:	.long	0x0049504c,0x0040ff80
 		.long	0x00000000+.Liplccws
 .Lschib:        .long   0x00000000,0x00000000
 		.long   0x00000000,0x00000000
diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- v2.4.6/linux/arch/s390/kernel/smp.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/smp.c	Wed Jul  4 11:50:39 2001
@@ -420,6 +420,7 @@
 void smp_ptlb_all(void)
 {
         smp_ext_call_others(smp_ptlb_callback, NULL, 1);
+	local_flush_tlb();
 }
 
 /*
@@ -522,8 +523,7 @@
  */
 {
         if (atomic_read(&smp_commenced) != 0)
-                smp_ext_call_others(func, info, 1);
-        (func)(info);
+                smp_ext_call_others(func, info, wait);
         return 0;
 }
 
@@ -776,3 +776,4 @@
 EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
+EXPORT_SYMBOL(smp_num_cpus);
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S
--- v2.4.6/linux/arch/s390x/kernel/entry.S	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/entry.S	Wed Jul  4 11:50:39 2001
@@ -632,8 +632,6 @@
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
-	stmg    %r14,%r15,__LC_SAVE_AREA
-        stam    %a2,%a4,__LC_SAVE_AREA+16
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jz      pgm_sv                   # skip if not
         tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
@@ -642,29 +640,10 @@
         clc     __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
         je      pgm_svcper
 # no interesting special case, ignore PER event
-        lm      %r13,%r15,__LC_SAVE_AREA
 	lpswe   __LC_PGM_OLD_PSW
 # it was a single stepped SVC that is causing all the trouble
 pgm_svcper:
-        tm      __LC_SVC_OLD_PSW+1,0x01  # test problem state bit
-	jz	0f                       # skip stack & access regs setup
-	lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
-        slr     %r14,%r14
-        sar     %a2,%r14                 # set ac.reg. 2 to primary space
-        lhi     %r14,1   
-        sar     %a4,%r14                 # and access reg. 4 to home space
-0:	aghi    %r15,-SP_SIZE            # make room for registers & psw
-        nill    %r15,0xfff8              # align stack pointer to 8
-        stmg    %r0,%r14,SP_R0(%r15)     # store gprs 0-14 to kernel stack 
-        stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R14(16,%r15),__LC_SAVE_AREA         # move R14-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
-        mvc     SP_PSW(16,%r15),__LC_PGM_OLD_PSW      # move user PSW to stack
-        lhi     %r0,__LC_SVC_OLD_PSW     # store trap indication
-        st      %r0,SP_TRAP(%r15)
-        xc      0(8,%r15),0(%r15)        # clear back chain
-
+	SAVE_ALL __LC_SVC_OLD_PSW
         mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
         j       pgm_system_call          # now do the svc
 pgm_svcret:
@@ -674,24 +653,7 @@
         mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
 	j       pgm_no_sv
 pgm_sv:
-        tm      __LC_PGM_OLD_PSW+1,0x01  # test problem state bit
-	jz	1f		         # skip stack setup save
-	lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
-        slr     %r14,%r14
-        sar     %a2,%r14                 # set ac.reg. 2 to primary space
-        lhi     %r14,1
-        sar     %a4,%r14                 # set access reg. 4 to home space
-1:	aghi    %r15,-SP_SIZE            # make room for registers & psw
-        nill    %r15,0xfff8              # align stack pointer to 8
-        stmg    %r0,%r14,SP_R0(%r15)     # store gprs 0-14 to kernel stack
-        stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R14(16,%r15),__LC_SAVE_AREA         # move R14-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
-        mvc     SP_PSW(16,%r15),__LC_PGM_OLD_PSW      # move user PSW to stack
-        lhi     %r0,__LC_PGM_OLD_PSW     # store trap indication
-        st      %r0,SP_TRAP(%r15)
-        xc      0(8,%r15),0(%r15)        # clear back chain
+	SAVE_ALL __LC_PGM_OLD_PSW
         mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
         llgh    %r7,__LC_PGM_ILC         # load instruction length
 	GET_CURRENT
@@ -823,8 +785,10 @@
         .globl restart_int_handler
 restart_int_handler:
         lg      %r15,__LC_KERNEL_STACK # load ksp
-        lctlg   %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
-        lam     %a0,%a15,__LC_AREGS_SAVE_AREA
+        lhi     %r10,__LC_CREGS_SAVE_AREA
+        lctlg   %c0,%c15,0(%r10) # get new ctl regs
+        lhi     %r10,__LC_AREGS_SAVE_AREA
+        lam     %a0,%a15,0(%r10)
         stosm   0(%r15),0x04           # now we can turn dat on
         lmg     %r6,%r15,48(%r15)      # load registers from clone
 	jg      start_secondary
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S
--- v2.4.6/linux/arch/s390x/kernel/head.S	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/head.S	Wed Jul  4 11:50:39 2001
@@ -262,8 +262,7 @@
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
         l     %r12,.Lparm                      # pointer to parameter area
-        st    %r1,__LC_IPLDEV                  # store ipl device number
-        st    %r1,IPL_DEVICE+4-PARMAREA(%r12)
+        st    %r1,IPL_DEVICE+4-PARMAREA(%r12)  # store ipl device number
 
 #
 # load parameter file from ipl device
@@ -467,6 +466,8 @@
 	sam64				 # switch to 64 bit mode
 	lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
 	lg    %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
+					 # move IPL device to lowcore
+        mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
 
 #
 # find out memory size.
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/irq.c linux/arch/s390x/kernel/irq.c
--- v2.4.6/linux/arch/s390x/kernel/irq.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/irq.c	Wed Jul  4 11:50:39 2001
@@ -380,8 +380,11 @@
         /* For now, nothing... */
 }
 
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+#endif
+
 EXPORT_SYMBOL(global_bh_lock);
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c
--- v2.4.6/linux/arch/s390x/kernel/linux32.c	Thu Apr 26 14:10:16 2001
+++ linux/arch/s390x/kernel/linux32.c	Wed Jul  4 11:50:39 2001
@@ -897,24 +897,24 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-struct dqblk32 {
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u32 dqb_curblocks;
+struct mem_dqblk32 {
     __u32 dqb_ihardlimit;
     __u32 dqb_isoftlimit;
     __u32 dqb_curinodes;
+    __u32 dqb_bhardlimit;
+    __u32 dqb_bsoftlimit;
+    __u64 dqb_curspace;
     __kernel_time_t32 dqb_btime;
     __kernel_time_t32 dqb_itime;
 };
                                 
-extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, __kernel_caddr_t addr);
 
 asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
 {
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
-	struct dqblk d;
+	struct mem_dqblk d;
 	mm_segment_t old_fs;
 	char *spec;
 	
@@ -924,33 +924,35 @@
 	case Q_SETQUOTA:
 	case Q_SETUSE:
 	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
+		if (copy_from_user (&d, (struct mem_dqblk32 *)addr,
+				    sizeof (struct mem_dqblk32)))
 			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		d.dqb_itime = ((struct mem_dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct mem_dqblk32 *)&d)->dqb_btime;
 		break;
 	default:
 		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+				    id, (__kernel_caddr_t)addr);
 	}
 	spec = getname (special);
 	err = PTR_ERR(spec);
 	if (IS_ERR(spec)) return err;
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
+	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
 	set_fs (old_fs);
 	putname (spec);
+	if (err)
+		return err;
 	if (cmds == Q_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		((struct mem_dqblk32 *)&d)->dqb_itime = i;
+		((struct mem_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct mem_dqblk32 *)addr, &d,
+				  sizeof (struct mem_dqblk32)))
 			return -EFAULT;
 	}
-	return err;
+	return 0;
 }
 
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/reipl.S linux/arch/s390x/kernel/reipl.S
--- v2.4.6/linux/arch/s390x/kernel/reipl.S	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/reipl.S	Wed Jul  4 11:50:39 2001
@@ -73,7 +73,7 @@
 		.quad   0x0000000000000000
 .Liplccws:	.long   0x02000000,0x60000018
 		.long   0x08000008,0x20000001
-.Liplorb:	.long	0x0049504c,0x0000ff80
+.Liplorb:	.long	0x0049504c,0x0040ff80
 		.long	0x00000000+.Liplccws
 .Lschib:        .long   0x00000000,0x00000000
 		.long   0x00000000,0x00000000
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c
--- v2.4.6/linux/arch/s390x/kernel/smp.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/smp.c	Wed Jul  4 11:50:39 2001
@@ -510,8 +510,7 @@
  */
 {
         if (atomic_read(&smp_commenced) != 0)
-                smp_ext_call_others(func, info, 1);
-        (func)(info);
+                smp_ext_call_others(func, info, wait);
         return 0;
 }
 
diff -u --recursive --new-file v2.4.6/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c
--- v2.4.6/linux/arch/s390x/mm/fault.c	Thu Apr 26 14:10:16 2001
+++ linux/arch/s390x/mm/fault.c	Wed Jul  4 11:50:39 2001
@@ -33,6 +33,34 @@
 
 extern void die(const char *,struct pt_regs *,long);
 
+extern spinlock_t timerlist_lock;
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out
+ */
+void bust_spinlocks(int yes)
+{
+        spin_lock_init(&timerlist_lock);
+        if (yes) {
+                oops_in_progress = 1;
+#ifdef CONFIG_SMP
+                atomic_set(&global_irq_lock,0);
+#endif
+        } else {
+                int loglevel_save = console_loglevel;
+                oops_in_progress = 0;
+                /*
+                 * OK, the message is on the console.  Now we call printk()
+                 * without oops_in_progress set so that printk will give klogd
+                 * a poke.  Hold onto your hats...
+                 */
+                console_loglevel = 15;          /* NMI oopser may have shut the console up */
+                printk(" ");
+                console_loglevel = loglevel_save;
+        }
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
diff -u --recursive --new-file v2.4.6/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.4.6/linux/drivers/block/ll_rw_blk.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/block/ll_rw_blk.c	Sun Jul  8 19:35:19 2001
@@ -365,6 +365,11 @@
 	 */
 	for (i = 0; i < queue_nr_requests; i++) {
 		rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL);
+		if (rq == NULL) {
+			/* We'll get a `leaked requests' message from blk_cleanup_queue */
+			printk(KERN_EMERG "blk_init_free_list: error allocating requests\n");
+			break;
+		}
 		memset(rq, 0, sizeof(struct request));
 		rq->rq_status = RQ_INACTIVE;
 		list_add(&rq->table, &q->request_freelist[i & 1]);
@@ -962,6 +967,7 @@
 {
 	mark_buffer_uptodate(bh, uptodate);
 	unlock_buffer(bh);
+	atomic_dec(&bh->b_count);
 }
 
 /**
@@ -1050,6 +1056,7 @@
 			continue;
 
 		/* We have the buffer lock */
+		atomic_inc(&bh->b_count);
 		bh->b_end_io = end_buffer_io_sync;
 
 		switch(rw) {
diff -u --recursive --new-file v2.4.6/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.4.6/linux/drivers/block/ps2esdi.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/block/ps2esdi.c	Sat Jul  7 11:39:05 2001
@@ -117,6 +117,7 @@
 static char ps2esdi_valid[MAX_HD];
 static int ps2esdi_sizes[MAX_HD << 6];
 static int ps2esdi_blocksizes[MAX_HD << 6];
+static int ps2esdi_maxsect[MAX_HD << 6];
 static int ps2esdi_drives;
 static struct hd_struct ps2esdi[MAX_HD << 6];
 static u_short io_base;
diff -u --recursive --new-file v2.4.6/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.4.6/linux/drivers/block/rd.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/rd.c	Wed Jul  4 14:41:33 2001
@@ -466,7 +466,7 @@
  *	romfs
  * 	gzip
  */
-int __init 
+static int __init 
 identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
 {
 	const int size = 512;
diff -u --recursive --new-file v2.4.6/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.4.6/linux/drivers/cdrom/mcd.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/cdrom/mcd.c	Wed Jul  4 11:50:39 2001
@@ -105,17 +105,17 @@
 #define mcd_port mcd    /* for compatible parameter passing with "insmod" */
 #include "mcd.h"
 
-static int mcd_blocksizes[1] = { 0, };
+static int mcd_blocksizes[1];
 
 
 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
-static int mcdDouble = 0; 
+static int mcdDouble; 
 
 /* How many sectors to hold at 1x speed counter */
-static int mcd1xhold = 0;
+static int mcd1xhold;
 
 /* Is the drive connected properly and responding?? */
-static int mcdPresent = 0;
+static int mcdPresent;
 
 #if 0
 #define TEST1 /* <int-..> */
@@ -162,7 +162,7 @@
 #define WORK_AROUND_MITSUMI_BUG_92
 #define WORK_AROUND_MITSUMI_BUG_93
 #ifdef WORK_AROUND_MITSUMI_BUG_93
-int mitsumi_bug_93_wait = 0;
+int mitsumi_bug_93_wait;
 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
 
 static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
diff -u --recursive --new-file v2.4.6/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.4.6/linux/drivers/char/Config.in	Tue Jul  3 17:08:19 2001
+++ linux/drivers/char/Config.in	Wed Jul  4 14:41:33 2001
@@ -42,8 +42,8 @@
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       dep_tristate '  Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
    fi
-   dep_tristate '  Microgate SyncLink card support' CONFIG_SYNCLINK m
-   dep_tristate '  HDLC line discipline support' CONFIG_N_HDLC m
+   tristate '  Microgate SyncLink card support' CONFIG_SYNCLINK
+   tristate '  HDLC line discipline support' CONFIG_N_HDLC
    tristate '  SDL RISCom/8 card support' CONFIG_RISCOM8
    tristate '  Specialix IO8+ card support' CONFIG_SPECIALIX
    if [ "$CONFIG_SPECIALIX" != "n" ]; then
@@ -60,6 +60,9 @@
      tristate '    Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
 fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
+   tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
+fi
 if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
    bool 'DC21285 serial port support' CONFIG_SERIAL_21285
    if [ "$CONFIG_SERIAL_21285" = "y" ]; then
@@ -135,6 +138,7 @@
    tristate '  Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
    tristate '  Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
+   tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
    tristate '  Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
    if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
@@ -169,6 +173,9 @@
 tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
 tristate 'Siemens R3964 line discipline' CONFIG_R3964
 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Sony Vaio Programmable I/O Control Device support' CONFIG_SONYPI $CONFIG_PCI
+fi
 
 mainmenu_option next_comment
 comment 'Ftape, the floppy tape device driver'
diff -u --recursive --new-file v2.4.6/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.4.6/linux/drivers/char/Makefile	Wed May 16 10:27:02 2001
+++ linux/drivers/char/Makefile	Wed Jul  4 14:41:33 2001
@@ -23,7 +23,7 @@
 
 export-objs     :=	busmouse.o console.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o \
-			tty_io.o
+			sonypi.o tty_io.o tty_ioctl.o
 
 mod-subdirs	:=	joystick ftape drm pcmcia
 
@@ -48,6 +48,20 @@
   SERIAL   =
 endif
 
+ifeq ($(ARCH),s390)
+  KEYMAP   =
+  KEYBD    =
+  CONSOLE  =
+  SERIAL   =
+endif
+
+ifeq ($(ARCH),s390x)
+  KEYMAP   =
+  KEYBD    =
+  CONSOLE  =
+  SERIAL   =
+endif
+
 ifeq ($(ARCH),m68k)
    ifdef CONFIG_AMIGA
       KEYBD = amikeyb.o
@@ -139,6 +153,7 @@
 obj-$(CONFIG_N_HDLC) += n_hdlc.o
 obj-$(CONFIG_SPECIALIX) += specialix.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
+obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
 obj-$(CONFIG_SX) += sx.o generic_serial.o
 obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
 obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o
@@ -162,6 +177,7 @@
 obj-$(CONFIG_DTLK) += dtlk.o
 obj-$(CONFIG_R3964) += n_r3964.o
 obj-$(CONFIG_APPLICOM) += applicom.o
+obj-$(CONFIG_SONYPI) += sonypi.o
 obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o
 obj-$(CONFIG_82C710_MOUSE) += qpmouse.o
 obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
diff -u --recursive --new-file v2.4.6/linux/drivers/char/dtlk.c linux/drivers/char/dtlk.c
--- v2.4.6/linux/drivers/char/dtlk.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/char/dtlk.c	Wed Jul  4 14:41:33 2001
@@ -128,7 +128,7 @@
 {
 	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	char ch;
-	int retval, i = 0, retries;
+	int i = 0, retries;
 
 	/* Can't seek (pread) on the DoubleTalk.  */
 	if (ppos != &file->f_pos)
@@ -144,8 +144,8 @@
 		while (i < count && dtlk_readable()) {
 			ch = dtlk_read_lpc();
 			/*        printk("dtlk_read() reads 0x%02x\n", ch); */
-			if ((retval = put_user(ch, buf++)))
-				return retval;
+			if (put_user(ch, buf++))
+				return -EFAULT;
 			i++;
 		}
 		if (i)
@@ -163,7 +163,7 @@
 static ssize_t dtlk_write(struct file *file, const char *buf,
 			  size_t count, loff_t * ppos)
 {
-	int i = 0, retries = 0, err, ch;
+	int i = 0, retries = 0, ch;
 
 	TRACE_TEXT("(dtlk_write");
 #ifdef TRACING
@@ -171,7 +171,8 @@
 	{
 		int i, ch;
 		for (i = 0; i < count; i++) {
-			err = get_user(ch, buf + i);
+			if (get_user(ch, buf + i))
+				return -EFAULT;
 			if (' ' <= ch && ch <= '~')
 				printk("%c", ch);
 			else
@@ -189,7 +190,7 @@
 		return -EINVAL;
 
 	while (1) {
-		while (i < count && (err = get_user(ch, buf)) == 0 &&
+		while (i < count && !get_user(ch, buf) &&
 		       (ch == DTLK_CLEAR || dtlk_writeable())) {
 			dtlk_write_tts(ch);
 			buf++;
@@ -279,7 +280,6 @@
 		      unsigned long arg)
 {
 	struct dtlk_settings *sp;
-	int err;
 	char portval;
 	TRACE_TEXT(" dtlk_ioctl");
 
@@ -287,9 +287,8 @@
 
 	case DTLK_INTERROGATE:
 		sp = dtlk_interrogate();
-		err = copy_to_user((char *) arg, (char *) sp,
-				   sizeof(struct dtlk_settings));
-		if (err)
+		if (copy_to_user((char *) arg, (char *) sp,
+				   sizeof(struct dtlk_settings)))
 			return -EINVAL;
 		return 0;
 
diff -u --recursive --new-file v2.4.6/linux/drivers/char/dz.c linux/drivers/char/dz.c
--- v2.4.6/linux/drivers/char/dz.c	Fri Mar  2 18:38:37 2001
+++ linux/drivers/char/dz.c	Wed Jul  4 14:41:33 2001
@@ -14,6 +14,8 @@
  *    after patches by harald to irq code.  
  * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
  *            field from "current" - somewhere between 2.1.121 and 2.1.131
+Qua Jun 27 15:02:26 BRT 2001
+ * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
  *  
  * Parts (C) 1999 David Airlie, airlied@linux.ie 
  * [07-SEP-99] Bugfixes 
@@ -835,7 +837,7 @@
   tmp.close_delay = info->close_delay;
   tmp.closing_wait = info->closing_wait;
   
-  return copy_to_user (retinfo, &tmp, sizeof(*retinfo));
+  return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
 }
 
 static int set_serial_info (struct dz_serial *info, struct serial_struct *new_info)
@@ -919,9 +921,9 @@
   restore_flags (flags);
 }
 
-static int dz_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+static int dz_ioctl (struct tty_struct *tty, struct file *file,
+		     unsigned int cmd, unsigned long arg)
 {
-  int error;
   struct dz_serial * info = (struct dz_serial *)tty->driver_data;
   int retval;
 
@@ -951,41 +953,26 @@
     return 0;
 
   case TIOCGSOFTCAR:
-    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long));
-    if (error)
-      return error;
-    put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
-    return 0;
+    return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
 
   case TIOCSSOFTCAR:
-    error = get_user (arg, (unsigned long *)arg);
-    if (error)
-      return error;
+    if (get_user (arg, (unsigned long *)arg))
+      return -EFAULT;
     tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
     return 0;
 
   case TIOCGSERIAL:
-    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct));
-    if (error)
-      return error;
     return get_serial_info (info, (struct serial_struct *)arg);
 
   case TIOCSSERIAL:
     return set_serial_info (info, (struct serial_struct *) arg);
 
   case TIOCSERGETLSR: /* Get line status register */
-    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(unsigned int));
-    if (error)
-      return error;
-    else
-      return get_lsr_info (info, (unsigned int *)arg);
+    return get_lsr_info (info, (unsigned int *)arg);
 
   case TIOCSERGSTRUCT:
-    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct dz_serial));
-    if (error)
-      return error;
-    copy_to_user((struct dz_serial *)arg, info, sizeof(struct dz_serial));
-    return 0;
+    return copy_to_user((struct dz_serial *)arg, info,
+		        sizeof(struct dz_serial)) ? -EFAULT : 0;
     
   default:
     return -ENOIOCTLCMD;
@@ -1436,7 +1423,7 @@
  * dz_console_print ()
  *
  * dz_console_print is registered for printk.
- * The console_lock must be held when we get here.
+ * The console must be locked when we get here.
  * ------------------------------------------------------------------- 
  */
 static void dz_console_print (struct console *cons, 
diff -u --recursive --new-file v2.4.6/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c
--- v2.4.6/linux/drivers/char/generic_serial.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/char/generic_serial.c	Wed Jul  4 14:41:33 2001
@@ -344,7 +344,7 @@
 	struct gs_port *port = ptr;
 	long end_jiffies;
 	int jiffies_to_transmit, charsleft = 0, rv = 0;
-	int to, rcib;
+	int rcib;
 
 	func_enter();
 
@@ -368,6 +368,7 @@
 		return rv;
 	}
 	/* stop trying: now + twice the time it would normally take +  seconds */
+	if (timeout == 0) timeout = MAX_SCHEDULE_TIMEOUT;
 	end_jiffies  = jiffies; 
 	if (timeout !=  MAX_SCHEDULE_TIMEOUT)
 		end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0;
@@ -376,11 +377,9 @@
 	gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", 
 		    jiffies, end_jiffies, end_jiffies-jiffies); 
 
-	to = 100;
 	/* the expression is actually jiffies < end_jiffies, but that won't
 	   work around the wraparound. Tricky eh? */
-	while (to-- &&
-	       (charsleft = gs_real_chars_in_buffer (port->tty)) &&
+	while ((charsleft = gs_real_chars_in_buffer (port->tty)) &&
 	        time_after (end_jiffies, jiffies)) {
 		/* Units check: 
 		   chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies!
@@ -1059,6 +1058,19 @@
 	copy_to_user(sp, &sio, sizeof(struct serial_struct));
 }
 
+
+void gs_got_break(struct gs_port *port)
+{
+	if (port->flags & ASYNC_SAK) {
+		do_SAK (port->tty);
+	}
+	*(port->tty->flip.flag_buf_ptr) = TTY_BREAK;
+	port->tty->flip.flag_buf_ptr++;
+	port->tty->flip.char_buf_ptr++;
+	port->tty->flip.count++;
+}
+
+
 EXPORT_SYMBOL(gs_put_char);
 EXPORT_SYMBOL(gs_write);
 EXPORT_SYMBOL(gs_write_room);
@@ -1075,4 +1087,4 @@
 EXPORT_SYMBOL(gs_init_port);
 EXPORT_SYMBOL(gs_setserial);
 EXPORT_SYMBOL(gs_getserial);
-
+EXPORT_SYMBOL(gs_got_break);
diff -u --recursive --new-file v2.4.6/linux/drivers/char/h8.c linux/drivers/char/h8.c
--- v2.4.6/linux/drivers/char/h8.c	Wed Jul 12 21:58:42 2000
+++ linux/drivers/char/h8.c	Wed Jul  4 14:41:33 2001
@@ -54,9 +54,9 @@
 /*
  * Forward declarations.
  */
-static int   h8_init(void);
-int          h8_display_blank(void);
-int          h8_display_unblank(void);
+static int  h8_init(void);
+static int  h8_display_blank(void);
+static int  h8_display_unblank(void);
 
 static void  h8_intr(int irq, void *dev_id, struct pt_regs *regs);
 
@@ -106,10 +106,10 @@
 
 static char  driver_version[] = "X0.0";/* no spaces */
 
-union	intr_buf intrbuf;
-int	intr_buf_ptr;
-union   intr_buf xx;	
-u_char  last_temp;
+static union	intr_buf intrbuf;
+static int	intr_buf_ptr;
+static union   intr_buf xx;	
+static u_char  last_temp;
 
 /*
  * I/O Macros for register reads and writes.
@@ -122,40 +122,40 @@
 #define WRITE_DATA(d)	H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
 #define WRITE_CMD(d)	H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
 
-unsigned int h8_base = H8_BASE_ADDR;
-unsigned int h8_irq = H8_IRQ;
-unsigned int h8_state = H8_IDLE;
-unsigned int h8_index = -1;
-unsigned int h8_enabled = 0;
-
-LIST_HEAD(h8_actq);
-LIST_HEAD(h8_cmdq);
-LIST_HEAD(h8_freeq);
+static unsigned int h8_base = H8_BASE_ADDR;
+static unsigned int h8_irq = H8_IRQ;
+static unsigned int h8_state = H8_IDLE;
+static unsigned int h8_index = -1;
+static unsigned int h8_enabled = 0;
+
+static LIST_HEAD(h8_actq);
+static LIST_HEAD(h8_cmdq);
+static LIST_HEAD(h8_freeq);
 
 /* 
  * Globals used in thermal control of Alphabook1.
  */
-int cpu_speed_divisor = -1;			
-int h8_event_mask = 0;			
-DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
-unsigned int h8_command_mask = 0;
-int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
-int h8_uthermal_window = UTH_HYSTERESIS;		      
-int h8_debug = 0xfffffdfc;
-int h8_ldamp = MHZ_115;
-int h8_udamp = MHZ_57;
-u_char h8_current_temp = 0;
-u_char h8_system_temp = 0;
-int h8_sync_channel = 0;
-DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
-int h8_init_performed;
+static int cpu_speed_divisor = -1;			
+static int h8_event_mask = 0;			
+static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
+static unsigned int h8_command_mask = 0;
+static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
+static int h8_uthermal_window = UTH_HYSTERESIS;		      
+static int h8_debug = 0xfffffdfc;
+static int h8_ldamp = MHZ_115;
+static int h8_udamp = MHZ_57;
+static u_char h8_current_temp = 0;
+static u_char h8_system_temp = 0;
+static int h8_sync_channel = 0;
+static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
+static int h8_init_performed;
 
 /* CPU speeds and clock divisor values */
-int speed_tab[6] = {230, 153, 115, 57, 28, 14};
+static int speed_tab[6] = {230, 153, 115, 57, 28, 14};
   
 /*
  * H8 interrupt handler
- */
+  */
 static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	u_char	stat_reg, data_reg;
@@ -377,7 +377,7 @@
 }
 
 /* Called from console driver -- must make sure h8_enabled. */
-int h8_display_blank(void)
+static int h8_display_blank(void)
 {
 #ifdef CONFIG_H8_DISPLAY_BLANK
         int     error;
@@ -393,7 +393,7 @@
 }
 
 /* Called from console driver -- must make sure h8_enabled. */
-int h8_display_unblank(void)
+static int h8_display_unblank(void)
 {
 #ifdef CONFIG_H8_DISPLAY_BLANK
         int error;
@@ -408,8 +408,7 @@
         return 0;
 }
 
-int
-h8_alloc_queues(void)
+static int h8_alloc_queues(void)
 {
         h8_cmd_q_t *qp;
 	unsigned long flags;
@@ -419,7 +418,7 @@
 				   GFP_KERNEL);
 
         if (!qp) {
-                printk("H8: could not allocate memory for command queue\n");
+                printk(KERN_ERR "H8: could not allocate memory for command queue\n");
                 return(0);
         }
         /* add to the free queue */
@@ -560,14 +559,14 @@
 {
 
         if(h8_debug & 0x200)
-                printk("h8_read_event_status: value 0x%x\n", intrbuf.word);
+                printk(KERN_DEBUG "h8_read_event_status: value 0x%x\n", intrbuf.word);
 
         /*
          * Power related items
          */
         if (intrbuf.word & H8_DC_CHANGE) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: DC_CHANGE\n");
+		    printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n");
                 /* see if dc added or removed, set batt/dc flag, send event */
 
                 h8_set_event_mask(H8_MANAGE_BATTERY);
@@ -575,7 +574,7 @@
         }
 
         if (intrbuf.word & H8_POWER_BUTTON) {
-                printk("Power switch pressed - please wait - preparing to power 
+                printk(KERN_CRIT "Power switch pressed - please wait - preparing to power 
 off\n");
                 h8_set_event_mask(H8_POWER_BUTTON);
                 wake_up(&h8_monitor_wait);
@@ -586,7 +585,7 @@
          */
         if (intrbuf.word & H8_THERMAL_THRESHOLD) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: THERMAL_THRESHOLD\n");
+		    printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLD\n");
                 h8_set_event_mask(H8_MANAGE_UTHERM);
                 wake_up(&h8_monitor_wait);
         }
@@ -596,67 +595,67 @@
          */
         if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: DOCKING_STATION_STATUS\n");
+		    printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUS\n");
                 /* read_ext_status */
         }
         if (intrbuf.word & H8_EXT_BATT_STATUS) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: EXT_BATT_STATUS\n");
+		    printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n");
 
         }
         if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
+		    printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
 
         }
         if (intrbuf.word & H8_BATT_CHANGE_OVER) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: BATT_CHANGE_OVER\n");
+		    printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n");
 
         }
         if (intrbuf.word & H8_WATCHDOG) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: WATCHDOG\n");
+		    printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n");
                 /* nop */
         }
         if (intrbuf.word & H8_SHUTDOWN) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: SHUTDOWN\n");
+		    printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n");
                 /* nop */
         }
         if (intrbuf.word & H8_KEYBOARD) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: KEYBOARD\n");
+		    printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n");
                 /* nop */
         }
         if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
+		    printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
                 /* read_ext_status*/
         }
         if (intrbuf.word & H8_INT_BATT_LOW) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: INT_BATT_LOW\n");
-                /* post event, warn user */
+		    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); post
+                /* event, warn user */
         }
         if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n");
+		    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATE\n");
                 /* nop - happens often */
         }
         if (intrbuf.word & H8_INT_BATT_STATUS) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: INT_BATT_STATUS\n");
+		    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n");
 
         }
         if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
+		    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
                 /* nop - happens often */
         }
         if (intrbuf.word & H8_EXT_BATT_LOW) {
 		if(h8_debug & 0x4)
-		    printk("h8_read_event_status: EXT_BATT_LOW\n");
+		    printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n");
                 /*if no internal, post event, warn user */
                 /* else nop */
         }
@@ -667,7 +666,7 @@
 /*
  * Function called when H8 has performed requested command.
  */
-void
+static void
 h8_cmd_done(h8_cmd_q_t *qp)
 {
 
@@ -675,14 +674,14 @@
         switch (qp->cmdbuf[0]) {
 	case H8_SYNC:
 	    if (h8_debug & 0x40000) 
-	        printk("H8: Sync command done - byte returned was 0x%x\n", 
+	        printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%x\n", 
 		       qp->rcvbuf[0]);
 	    list_add(&qp->link, &h8_freeq);
 	    break;
 
 	case H8_RD_SN:
 	case H8_RD_ENET_ADDR:
-	    printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", 
+	    printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", 
 		   qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
 		   qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
 	    list_add(&qp->link, &h8_freeq);
@@ -691,13 +690,13 @@
 	case H8_RD_HW_VER:
 	case H8_RD_MIC_VER:
 	case H8_RD_MAX_TEMP:
-	    printk("H8: Max recorded CPU temp %d, Sys temp %d\n",
+	    printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %d\n",
 		   qp->rcvbuf[0], qp->rcvbuf[1]);
 	    list_add(&qp->link, &h8_freeq);
 	    break;
 
 	case H8_RD_MIN_TEMP:
-	    printk("H8: Min recorded CPU temp %d, Sys temp %d\n",
+	    printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %d\n",
 		   qp->rcvbuf[0], qp->rcvbuf[1]);
 	    list_add(&qp->link, &h8_freeq);
 	    break;
@@ -712,11 +711,11 @@
 
 	case H8_RD_SYS_VARIENT:
 	case H8_RD_PWR_ON_CYCLES:
-	    printk(" H8: RD_PWR_ON_CYCLES command done\n");
+	    printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command done\n");
 	    break;
 
 	case H8_RD_PWR_ON_SECS:
-	    printk("H8: RD_PWR_ON_SECS command done\n");
+	    printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n");
 	    break;
 
 	case H8_RD_RESET_STATUS:
@@ -741,7 +740,7 @@
 	case H8_RD_NEW_BUSY_SPEED:
 	case H8_RD_CONFIG_INTERFACE:
 	case H8_RD_INT_BATT_STATUS:
-	    printk("H8: Read int batt status cmd done - returned was %x %x %x\n",
+	    printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %x\n",
 		   qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
 	    list_add(&qp->link, &h8_freeq);
 	    break;
@@ -752,7 +751,7 @@
 	case H8_CTL_EMU_BITPORT:
 	case H8_DEVICE_CONTROL:
 	    if(h8_debug & 0x20000) {
-	        printk("H8: Device control cmd done - byte returned was 0x%x\n",
+	        printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%x\n",
 		       qp->rcvbuf[0]);
 	    }
 	    list_add(&qp->link, &h8_freeq);
@@ -767,7 +766,7 @@
 	case H8_CTL_MOUSE_SENSITIVITY:
 	case H8_CTL_DIAG_MODE:
 	case H8_CTL_IDLE_AND_BUSY_SPDS:
-	    printk("H8: Idle and busy speed command done\n");
+	    printk(KERN_DEBUG "H8: Idle and busy speed command done\n");
 	    break;
 
 	case H8_CTL_TFT_BRT_BATT:
@@ -808,7 +807,7 @@
 	case H8_BQ_RD_REG:
 	case H8_BQ_WRT_REG:
 	case H8_PWR_OFF:
-	    printk ("H8: misc command completed\n");
+	    printk (KERN_DEBUG "H8: misc command completed\n");
 	    break;
         }
         return;
@@ -948,7 +947,7 @@
          */
         h8_get_curr_temp(curr_temp);
 
-        printk("H8: Initial CPU temp: %d\n", curr_temp[0]);
+        printk(KERN_INFO "H8: Initial CPU temp: %d\n", curr_temp[0]);
 
         if(curr_temp[0] >= h8_uthermal_threshold) {
                 h8_set_event_mask(H8_MANAGE_UTHERM);
@@ -965,7 +964,7 @@
 		sleep_on(&h8_monitor_wait);
 
                 if(h8_debug & 0x2)
-                        printk("h8_monitor_thread awakened, mask:%x\n",
+                        printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%x\n",
                                 h8_event_mask);
 
                 if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
@@ -1008,7 +1007,7 @@
         if(h8_event_mask & H8_MANAGE_UTHERM) {
 		/* Upper thermal interrupt received, need to cool down. */
 		if(h8_debug & 0x10)
-                        printk("H8: Thermal threshold %d F reached\n",
+                        printk(KERN_WARNING "H8: Thermal threshold %d F reached\n",
 			       h8_uthermal_threshold);
 		h8_set_cpu_speed(h8_udamp); 
                 h8_clear_event_mask(H8_MANAGE_UTHERM);
@@ -1027,7 +1026,7 @@
                         h8_set_upper_therm_thold(h8_uthermal_threshold);
                         h8_set_cpu_speed(h8_ldamp); /* adjustable */ 
                         if(h8_debug & 0x10)
-                            printk("H8: CPU cool, applying cpu_divisor: %d \n",
+                            printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d \n",
 				   h8_ldamp);
                         h8_clear_event_mask(H8_MANAGE_LTHERM);
                 }
@@ -1082,7 +1081,7 @@
 #endif /* NOT_YET */
 
         if(h8_debug & 0x8)
-                printk("H8: Setting CPU speed to %d MHz\n",
+                printk(KERN_DEBUG "H8: Setting CPU speed to %d MHz\n",
 		       speed_tab[speed_divisor]); 
 
          /* Make the actual speed change */
@@ -1125,7 +1124,7 @@
                 break;
         }
         if(h8_debug & 0x8)
-                printk("H8: CPU speed current setting: %d MHz\n", speed); 
+                printk(KERN_DEBUG "H8: CPU speed current setting: %d MHz\n", speed); 
 #endif  /* NOT_YET */
 	return speed;
 }
diff -u --recursive --new-file v2.4.6/linux/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c
--- v2.4.6/linux/drivers/char/ip2/i2cmd.c	Mon Apr 24 13:39:35 2000
+++ linux/drivers/char/ip2/i2cmd.c	Wed Jul  4 14:41:33 2001
@@ -139,7 +139,7 @@
 //static UCHAR ct86[]={ 2, BTH,     0x56,0                   }; // RCV_ENABLE
 static UCHAR ct87[] = { 1, BYP,     0x57                     }; // HW_TEST
 //static UCHAR ct88[]={ 3, BTH,     0x58,0,0                 }; // RCV_THRESHOLD
-static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
+//static UCHAR ct89[]={ 1, BYP,     0x59                     }; // DSS_NOW
 //static UCHAR ct90[]={ 3, BYP,     0x5A,0,0                 }; // Set SILO
 //static UCHAR ct91[]={ 2, BYP,     0x5B,0                   }; // timed break
 
diff -u --recursive --new-file v2.4.6/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c
--- v2.4.6/linux/drivers/char/machzwd.c	Tue May 22 10:23:16 2001
+++ linux/drivers/char/machzwd.c	Wed Jul  4 14:41:33 2001
@@ -124,6 +124,7 @@
 static int zf_is_open = 0;
 static int zf_expect_close = 0;
 static spinlock_t zf_lock;
+static spinlock_t zf_port_lock;
 static struct timer_list zf_timer;
 static unsigned long next_heartbeat = 0;
 
@@ -140,7 +141,7 @@
 #ifndef ZF_DEBUG
 #	define dprintk(format, args...)
 #else
-#	define dprintk(format, args...) printk(KERN_DEBUG PFX ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args)
+#	define dprintk(format, args...) printk(KERN_DEBUG PFX; ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args)
 #endif
 
 
@@ -175,7 +176,7 @@
  *	Just get current counter value
  */
 
-inline unsigned short zf_get_timer(unsigned char n)
+static inline unsigned short zf_get_timer(unsigned char n)
 {
 	switch(n){
 		case WD1:
@@ -209,17 +210,20 @@
 static void zf_timer_off(void)
 {
 	unsigned int ctrl_reg = 0;
+	unsigned long flags;
 
 	/* stop internal ping */
-	del_timer(&zf_timer);
+	del_timer_sync(&zf_timer);
 
+	spin_lock_irqsave(&zf_port_lock, flags);
 	/* stop watchdog timer */	
 	ctrl_reg = zf_get_control();
 	ctrl_reg |= (ENABLE_WD1|ENABLE_WD2);	/* disable wd1 and wd2 */
 	ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2);
 	zf_set_control(ctrl_reg);
+	spin_unlock_irqrestore(&zf_port_lock, flags);
 
-	printk(PFX ": Watchdog timer is now disabled\n");
+	printk(KERN_INFO PFX ": Watchdog timer is now disabled\n");
 }
 
 
@@ -229,6 +233,9 @@
 static void zf_timer_on(void)
 {
 	unsigned int ctrl_reg = 0;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&zf_port_lock, flags);
 
 	zf_writeb(PULSE_LEN, 0xff);
 
@@ -246,15 +253,17 @@
 	ctrl_reg = zf_get_control();
 	ctrl_reg |= (ENABLE_WD1|zf_action);
 	zf_set_control(ctrl_reg);
+	spin_unlock_irqrestore(&zf_port_lock, flags);
 
-	printk(PFX ": Watchdog timer is now enabled\n");
+	printk(KERN_INFO PFX ": Watchdog timer is now enabled\n");
 }
 
 
 static void zf_ping(unsigned long data)
 {
 	unsigned int ctrl_reg = 0;
-
+	unsigned long flags;
+		
 	zf_writeb(COUNTER_2, 0xff);
 
 	if(time_before(jiffies, next_heartbeat)){
@@ -265,6 +274,8 @@
 		 * reset event is activated by transition from 0 to 1 on
 		 * RESET_WD1 bit and we assume that it is already zero...
 		 */
+
+		spin_lock_irqsave(&zf_port_lock, flags);
 		ctrl_reg = zf_get_control();    
 		ctrl_reg |= RESET_WD1;		
 		zf_set_control(ctrl_reg);	
@@ -272,11 +283,12 @@
 		/* ...and nothing changes until here */
 		ctrl_reg &= ~(RESET_WD1);
 		zf_set_control(ctrl_reg);		
+		spin_unlock_irqrestore(&zf_port_lock, flags);
 
 		zf_timer.expires = jiffies + ZF_HW_TIMEO;
 		add_timer(&zf_timer);
 	}else{
-		printk(PFX ": I will reset your machine\n");
+		printk(KERN_CRIT PFX ": I will reset your machine\n");
 	}
 }
 
@@ -396,7 +408,7 @@
 			zf_timer_off();
 		} else {
 			del_timer(&zf_timer);
-			printk(PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
+			printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
 		}
 		
 		spin_lock(&zf_lock);
@@ -427,9 +439,7 @@
 
 
 static struct file_operations zf_fops = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,34)
 	owner:          THIS_MODULE,
-#endif
 	read:           zf_read,
 	write:          zf_write,
 	ioctl:          zf_ioctl,
@@ -458,19 +468,19 @@
 {
 	char *str[] = { "RESET", "SMI", "NMI", "SCI" };
 	
-	printk(PFX ": Watchdog using action = %s\n", str[act]);
+	printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]);
 }
 
-int __init zf_init(void)
+static int __init zf_init(void)
 {
 	int ret;
 	
-	printk(PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
+	printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
 
 	ret = zf_get_ZFL_version();
 	printk("%#x\n", ret);
 	if((!ret) || (ret != 0xffff)){
-		printk(PFX ": no ZF-Logic found\n");
+		printk(KERN_WARNING PFX ": no ZF-Logic found\n");
 		return -ENODEV;
 	}
 
@@ -482,6 +492,7 @@
 	zf_show_action(action);
 
 	spin_lock_init(&zf_lock);
+	spin_lock_init(&zf_port_lock);
 	
 	ret = misc_register(&zf_miscdev);
 	if (ret){
@@ -490,22 +501,12 @@
 		goto out;
 	}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3)
-	if(check_region(ZF_IOBASE, 3)){
-#else
 	if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
-#endif
-
 		printk(KERN_ERR "cannot reserve I/O ports at %d\n",
 							ZF_IOBASE);
 		ret = -EBUSY;
 		goto no_region;
 	}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3)
-	request_region(ZF_IOBASE, 3, "MachZ ZFL WDT");
-#define __exit
-#endif
 
 	ret = register_reboot_notifier(&zf_notifier);
 	if(ret){
diff -u --recursive --new-file v2.4.6/linux/drivers/char/moxa.c linux/drivers/char/moxa.c
--- v2.4.6/linux/drivers/char/moxa.c	Tue May 22 10:23:16 2001
+++ linux/drivers/char/moxa.c	Wed Jul  4 14:41:33 2001
@@ -2916,6 +2916,8 @@
 	unsigned long baseAddr;
 	int i;
 
+	if(len > sizeof(moxaBuff))
+		return -EINVAL;
 	if(copy_from_user(moxaBuff, tmp, len))
 		return -EFAULT;
 	baseAddr = moxaBaseAddr[cardno];
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/linux_compat.h linux/drivers/char/rio/linux_compat.h
--- v2.4.6/linux/drivers/char/rio/linux_compat.h	Fri Aug 11 14:51:33 2000
+++ linux/drivers/char/rio/linux_compat.h	Wed Jul  4 14:41:33 2001
@@ -16,11 +16,13 @@
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <asm/hardirq.h>
+
 
 #define disable(oldspl) save_flags (oldspl)
 #define restore(oldspl) restore_flags (oldspl)
 
-#define sysbrk(x) kmalloc ((x), GFP_KERNEL)
+#define sysbrk(x) kmalloc ((x),in_interrupt()? GFP_ATOMIC : GFP_KERNEL)
 #define sysfree(p,size) kfree ((p))
 
 #define WBYTE(p,v) writeb(v, &p)
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c
--- v2.4.6/linux/drivers/char/rio/rio_linux.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/char/rio/rio_linux.c	Wed Jul  4 14:41:33 2001
@@ -58,6 +58,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/miscdevice.h>
+#include <linux/init.h>
 
 #include <linux/compatmac.h>
 #include <linux/generic_serial.h>
@@ -165,7 +166,7 @@
   /* startuptime */     HZ*2,           /* how long to wait for card to run */
   /* slowcook */        0,              /* TRUE -> always use line disc. */
   /* intrpolltime */    1,              /* The frequency of OUR polls */
-  /* breakinterval */   25,             /* x10 mS */
+  /* breakinterval */   25,             /* x10 mS XXX: units seem to be 1ms not 10! -- REW*/
   /* timer */           10,             /* mS */
   /* RtaLoadBase */     0x7000,
   /* HostLoadBase */    0x7C00,
@@ -203,11 +204,8 @@
 		         unsigned int cmd, unsigned long arg);
 static int rio_init_drivers(void);
 
-
 void my_hd (void *addr, int len);
 
-
-
 static struct tty_driver rio_driver, rio_callout_driver;
 static struct tty_driver rio_driver2, rio_callout_driver2;
 
@@ -248,14 +246,12 @@
 long rio_irqmask = -1;
 
 #ifndef TWO_ZERO
-#ifdef MODULE
 MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>");
 MODULE_DESCRIPTION("RIO driver");
 MODULE_PARM(rio_poll, "i");
 MODULE_PARM(rio_debug, "i");
 MODULE_PARM(rio_irqmask, "i");
 #endif
-#endif
 
 static struct real_driver rio_real_driver = {
   rio_disable_tx_interrupts,
@@ -383,8 +379,8 @@
 
 int rio_ismodem (kdev_t device)
 {
-  return (MAJOR (device) != RIO_NORMAL_MAJOR0) &&
-         (MAJOR (device) != RIO_NORMAL_MAJOR1);
+  return (MAJOR (device) == RIO_NORMAL_MAJOR0) ||
+         (MAJOR (device) == RIO_NORMAL_MAJOR1);
 }
 
 
@@ -455,7 +451,6 @@
   func_enter ();
 
   HostP = (struct Host*)ptr; /* &p->RIOHosts[(long)ptr]; */
-  
   rio_dprintk (RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", 
                irq, HostP->Ivec); 
 
@@ -624,8 +619,12 @@
 /* Nothing special here... */
 static void rio_shutdown_port (void * ptr) 
 {
+  struct Port *PortP;
+
   func_enter();
 
+  PortP = (struct Port *)ptr;
+  PortP->gs.tty = NULL;
 #if 0
   port->gs.flags &= ~ GS_ACTIVE;
   if (!port->gs.tty) {
@@ -654,8 +653,14 @@
    exit minicom.  I expect an "oops".  -- REW */
 static void rio_hungup (void *ptr)
 {
-  func_enter ();
+  struct Port *PortP;
+
+  func_enter();
+  
+  PortP = (struct Port *)ptr;
+  PortP->gs.tty = NULL;
   rio_dec_mod_count (); 
+
   func_exit ();
 }
 
@@ -679,9 +684,8 @@
     PortP->gs.count = 0; 
   }                
 
-
+  PortP->gs.tty = NULL;
   rio_dec_mod_count ();
-
   func_exit ();
 }
 
@@ -700,24 +704,28 @@
   return rc;
 }
 
+extern int RIOShortCommand(struct rio_info *p, struct Port *PortP,
+               int command, int len, int arg);
 
 static int rio_ioctl (struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
-#if 0
   int rc;
-  struct rio_port *port = tty->driver_data;
+  struct Port *PortP;
   int ival;
 
-  /* func_enter2(); */
+  func_enter();
 
+  PortP = (struct Port *)tty->driver_data;
 
   rc  = 0;
   switch (cmd) {
+#if 0
   case TIOCGSOFTCAR:
     rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
                   (unsigned int *) arg);
     break;
+#endif
   case TIOCSSOFTCAR:
     if ((rc = verify_area(VERIFY_READ, (void *) arg,
                           sizeof(int))) == 0) {
@@ -730,13 +738,39 @@
   case TIOCGSERIAL:
     if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
                           sizeof(struct serial_struct))) == 0)
-      gs_getserial(&port->gs, (struct serial_struct *) arg);
+      gs_getserial(&PortP->gs, (struct serial_struct *) arg);
+    break;
+  case TCSBRK:
+    if ( PortP->State & RIO_DELETED ) {
+      rio_dprintk (RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
+      rc = -EIO;      
+    } else {
+      if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) {
+         rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
+         rc = -EIO;
+      }          
+    }
+    break;
+  case TCSBRKP:
+    if ( PortP->State & RIO_DELETED ) {
+      rio_dprintk (RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
+      rc = -EIO;      
+    } else {
+      int l;
+      l = arg?arg*100:250;
+      if (l > 255) l = 255;
+      if (RIOShortCommand(p, PortP, SBREAK, 2, arg?arg*100:250) == RIO_FAIL) {
+         rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
+         rc = -EIO;
+      }          
+    }
     break;
   case TIOCSSERIAL:
     if ((rc = verify_area(VERIFY_READ, (void *) arg,
                           sizeof(struct serial_struct))) == 0)
-      rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+      rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg);
     break;
+#if 0
   case TIOCMGET:
     if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
                           sizeof(unsigned int))) == 0) {
@@ -768,17 +802,13 @@
                            ((ival & TIOCM_RTS) ? 1 : 0));
     }
     break;
-
+#endif
   default:
     rc = -ENOIOCTLCMD;
     break;
   }
-  /* func_exit(); */
+  func_exit();
   return rc;
-#else
-  return -ENOIOCTLCMD;
-#endif
-
 }
 
 
@@ -1029,17 +1059,15 @@
  free4:kfree (rio_termios);
  free3:kfree (p->RIOPortp);
  free2:kfree (p->RIOHosts);
- free1:kfree (p);
- free0:
-  if (p) {
-	rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", 
+ free1:
+  rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", 
         	       p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
-  }
+  kfree(p);        	      
+ free0:
   return -ENOMEM;
 }
 
-#ifdef MODULE
-static void rio_release_drivers(void)
+static void  __exit rio_release_drivers(void)
 {
   func_enter();
   tty_unregister_driver (&rio_callout_driver2);
@@ -1048,7 +1076,6 @@
   tty_unregister_driver (&rio_driver);
   func_exit();
 }
-#endif 
 
 #ifdef TWO_ZERO
 #define PDEV unsigned char pci_bus, unsigned pci_fun
@@ -1101,11 +1128,7 @@
 #endif
 
 
-#ifdef MODULE
-#define rio_init init_module
-#endif
-
-int rio_init(void) 
+static int __init rio_init(void) 
 {
   int found = 0;
   int i;
@@ -1255,6 +1278,7 @@
       hp->Type  = RIO_PCI;
       hp->Copy  = rio_pcicopy;
       hp->Mode  = RIO_PCI_BOOT_FROM_RAM;
+      hp->HostLock = SPIN_LOCK_UNLOCKED;
 
       rio_dprintk (RIO_DEBUG_PROBE, "Ivec: %x\n", hp->Ivec);
       rio_dprintk (RIO_DEBUG_PROBE, "Mode: %x\n", hp->Mode);
@@ -1310,6 +1334,7 @@
                              * Moreover, the ISA card will work with the 
                              * special PCI copy anyway. -- REW */
     hp->Mode = 0;
+    hp->HostLock = SPIN_LOCK_UNLOCKED;
 
     vpdp = get_VPD_PROM (hp);
     rio_dprintk (RIO_DEBUG_PROBE, "Got VPD ROM\n");
@@ -1388,8 +1413,7 @@
 }
 
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit rio_exit (void)
 {
   int i; 
   struct Host *hp;
@@ -1424,9 +1448,9 @@
 
   func_exit();
 }
-#endif
-
 
+module_init(rio_init);
+module_exit(rio_exit);
 
 /*
  * Anybody who knows why this doesn't work for me, please tell me -- REW.
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rio_linux.h linux/drivers/char/rio/rio_linux.h
--- v2.4.6/linux/drivers/char/rio/rio_linux.h	Mon Dec 11 12:50:43 2000
+++ linux/drivers/char/rio/rio_linux.h	Wed Jul  4 14:41:33 2001
@@ -95,28 +95,27 @@
 #if 1
 #define rio_spin_lock_irqsave(sem, flags) do { \
 	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \
-					sem, __FILE__, __LINE__);\
-        spin_lock_irqsave(sem, flags);\
-        } while (0)
+	                                sem, __FILE__, __LINE__);\
+	spin_lock_irqsave(sem, flags);\
+	} while (0)
 
 #define rio_spin_unlock_irqrestore(sem, flags) do { \
 	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\
-					sem, __FILE__, __LINE__);\
-        spin_unlock_irqrestore(sem, flags);\
-        } while (0)
-
+	                                sem, __FILE__, __LINE__);\
+	spin_unlock_irqrestore(sem, flags);\
+	} while (0)
 
 #define rio_spin_lock(sem) do { \
 	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\
-					sem, __FILE__, __LINE__);\
-        spin_lock(sem);\
-        } while (0)
+	                                sem, __FILE__, __LINE__);\
+	spin_lock(sem);\
+	} while (0)
 
 #define rio_spin_unlock(sem) do { \
 	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlock: %p %s:%d\n",\
-					sem, __FILE__, __LINE__);\
-        spin_unlock(sem);\
-        } while (0)
+	                                sem, __FILE__, __LINE__);\
+	spin_unlock(sem);\
+	} while (0)
 #else
 #define rio_spin_lock_irqsave(sem, flags) \
             spin_lock_irqsave(sem, flags)
@@ -165,7 +164,7 @@
 #define rio_memcpy_fromio                      memcpy_fromio
 #endif
 
-#define DEBUG
+#define DEBUG 1
 
 
 /* 
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rioboot.c linux/drivers/char/rio/rioboot.c
--- v2.4.6/linux/drivers/char/rio/rioboot.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/rioboot.c	Wed Jul  4 14:41:33 2001
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/interrupt.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/string.h>
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riocmd.c linux/drivers/char/rio/riocmd.c
--- v2.4.6/linux/drivers/char/rio/riocmd.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/riocmd.c	Wed Jul  4 14:41:33 2001
@@ -474,17 +474,18 @@
 	rio_spin_lock_irqsave(&PortP->portSem, flags);
 	switch( RBYTE(PktCmdP->Command) ) {
 		case BREAK_RECEIVED:
-		rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n");
+			rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n");
 			/* If the current line disc. is not multi-threading and
 	   			the current processor is not the default, reset rup_intr
 	   			and return FALSE to ensure that the command packet is
 	   			not freed. */
 			/* Call tmgr HANGUP HERE */
 			/* Fix this later when every thing works !!!! RAMRAJ */
+			gs_got_break (PortP);
 			break;
 
 		case COMPLETE:
-		rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n",
+			rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n",
 			     RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts);
 			subCommand = 1;
 			switch (RBYTE(PktCmdP->SubCommand)) {
@@ -549,6 +550,8 @@
 				*/
 				if (PortP->gs.tty == NULL)
 					break;
+				if (PortP->gs.tty->termios == NULL)
+					break;
 			  
 				if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) &&
 				((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) {
@@ -623,7 +626,8 @@
 	struct CmdBlk *CmdBlkP;
 
 	CmdBlkP = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk));
-	bzero(CmdBlkP, sizeof(struct CmdBlk));
+	if (CmdBlkP)
+		bzero(CmdBlkP, sizeof(struct CmdBlk));
 
 	return CmdBlkP;
 }
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riodrvr.h linux/drivers/char/rio/riodrvr.h
--- v2.4.6/linux/drivers/char/rio/riodrvr.h	Wed May 10 16:56:44 2000
+++ linux/drivers/char/rio/riodrvr.h	Wed Jul  4 14:41:33 2001
@@ -33,12 +33,13 @@
 #ifndef __riodrvr_h
 #define __riodrvr_h
 
+#include <asm/param.h>	/* for HZ */
+
 #ifdef SCCS_LABELS
 static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h	1.3";
 #endif
 
 #define MEMDUMP_SIZE	32
-#define HZ				100
 #define	MOD_DISABLE	(RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT)
 
 
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rioinit.c linux/drivers/char/rio/rioinit.c
--- v2.4.6/linux/drivers/char/rio/rioinit.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/rioinit.c	Wed Jul  4 14:41:33 2001
@@ -1446,7 +1446,7 @@
 				}
 				RIODefaultName(p, HostP, rup);
 			}
-			HostP->UnixRups[rup].RupLock = -1;
+			HostP->UnixRups[rup].RupLock = SPIN_LOCK_UNLOCKED;
 		}
 	}
 }
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c
--- v2.4.6/linux/drivers/char/rio/riotable.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/char/rio/riotable.c	Wed Jul  4 14:41:33 2001
@@ -37,6 +37,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/interrupt.h>
+
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/string.h>
@@ -499,7 +501,7 @@
 	struct Map *HostMapP;
 	struct Port *PortP;
 	int work_done = 0;
-	unsigned long flags;
+	unsigned long lock_flags, sem_flags;
 
 	rio_dprintk (RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n",
 								MapP->HostUniqueNum, MapP->RtaUniqueNum);
@@ -507,10 +509,10 @@
 	for ( host=0; host < p->RIONumHosts; host++ ) {
 		HostP = &p->RIOHosts[host];
 
-		rio_spin_lock_irqsave( &HostP->HostLock, flags );
+		rio_spin_lock_irqsave( &HostP->HostLock, lock_flags );
 
 		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) {
-			rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+			rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
 			continue;
 		}
 
@@ -527,7 +529,7 @@
 					if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) {
 						rio_dprintk (RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n");
 						p->RIOError.Error = UNIT_IS_IN_USE;
-						rio_spin_unlock_irqrestore( &HostP->HostLock, flags);
+						rio_spin_unlock_irqrestore( &HostP->HostLock, lock_flags);
 						return EBUSY;
 					}
 				}
@@ -542,7 +544,7 @@
 						PortP = p->RIOPortp[port];
 						rio_dprintk (RIO_DEBUG_TABLE, "Unmap port\n");
 
-						rio_spin_lock_irqsave( &PortP->portSem, flags );
+						rio_spin_lock_irqsave( &PortP->portSem, sem_flags );
 
 						PortP->Mapped = 0;
 
@@ -600,7 +602,7 @@
 							WWORD(PortP->PhbP->destination,
 							 dest_unit + (dest_port << 8));
 						}
-						rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+						rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags);
 					}
 				}
 				rio_dprintk (RIO_DEBUG_TABLE, "Entry nulled.\n");
@@ -608,7 +610,7 @@
 				work_done++;
 			}
 		}
-		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+		rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
 	}
 
 	/* XXXXX lock me up */
diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riotty.c linux/drivers/char/rio/riotty.c
--- v2.4.6/linux/drivers/char/rio/riotty.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/rio/riotty.c	Wed Jul  4 14:41:33 2001
@@ -96,7 +96,7 @@
 #endif
 
 static void RIOClearUp(struct Port *PortP);
-static int RIOShortCommand(struct rio_info *p, struct Port *PortP, 
+int RIOShortCommand(struct rio_info *p, struct Port *PortP, 
 			   int command, int len, int arg);
 
 
@@ -452,8 +452,11 @@
 				PortP->gs.tty->termios->c_state |= WOPEN;
 				*/
 				PortP->State |= RIO_WOPEN;
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				if (RIODelay (PortP, HUNDRED_MS) == RIO_FAIL)
 #if 0
 				if ( sleep((caddr_t)&tp->tm.c_canqo, TTIPRI|PCATCH))
+#endif
 				{
 					/*
 					** ACTION: verify that this is a good thing
@@ -471,7 +474,6 @@
 					func_exit ();
 					return -EINTR;
 				}
-#endif
 			}
 			PortP->State &= ~RIO_WOPEN;
 		}
@@ -527,8 +529,10 @@
 #endif
 	struct Port *PortP =ptr;	/* pointer to the port structure */
 	int deleted = 0;
-	int	try = 25;
-	int	repeat_this = 0xff;
+	int	try = -1; /* Disable the timeouts by setting them to -1 */
+	int	repeat_this = -1; /* Congrats to those having 15 years of 
+				     uptime! (You get to break the driver.) */
+	long end_time;
 	struct tty_struct * tty;
 	unsigned long flags;
 	int Modem;
@@ -541,6 +545,12 @@
 	/* tp = PortP->TtyP;*/			/* Get tty */
 	tty = PortP->gs.tty;
 	rio_dprintk (RIO_DEBUG_TTY, "TTY is at address 0x%x\n",(int)tty);
+
+	if (PortP->gs.closing_wait) 
+		end_time = jiffies + PortP->gs.closing_wait;
+	else 
+		end_time = jiffies + MAX_SCHEDULE_TIMEOUT;
+
 	Modem = rio_ismodem(tty->device);
 #if 0
 	/* What F.CKING cache? Even then, a higly idle multiprocessor,
@@ -573,7 +583,8 @@
 	** clear the open bits for this device
 	*/
 	PortP->State &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN);
-
+	PortP->State &= ~RIO_CARR_ON;
+	PortP->ModemState &= ~MSVR1_CD;
 	/*
 	** If the device was open as both a Modem and a tty line
 	** then we need to wimp out here, as the port has not really
@@ -605,7 +616,6 @@
 	*/
 	rio_dprintk (RIO_DEBUG_TTY, "Timeout 1 starts\n");
 
-#if 0
 	if (!deleted)
 	while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted && 
 		(PortP->TxBufferIn != PortP->TxBufferOut) ) {
@@ -626,7 +636,7 @@
 		}
 		rio_spin_lock_irqsave(&PortP->portSem, flags);
 	}
-#endif
+
 	PortP->TxBufferIn = PortP->TxBufferOut = 0;
 	repeat_this = 0xff;
 
@@ -662,7 +672,7 @@
 	if (!deleted)
 	  while (try && (PortP->PortState & PORT_ISOPEN)) {
 	        try--;
-		if (try == 0) {
+		if (time_after (jiffies, end_time)) {
 		  rio_dprintk (RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n" );
 		  RIOPreemptiveCmd(p, PortP,FCLOSE);
 		  break;
@@ -674,7 +684,11 @@
 			RIOClearUp( PortP );
 			goto close_end;
 		}
-		RIODelay_ni(PortP, HUNDRED_MS);
+		if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+			rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n");
+			RIOPreemptiveCmd(p, PortP,FCLOSE);
+			break;
+		}
 	}
 	rio_spin_lock_irqsave(&PortP->portSem, flags);
 	rio_dprintk (RIO_DEBUG_TTY, "Close: try was %d on completion\n", try );
@@ -779,7 +793,7 @@
 ** Other values of len aren't allowed, and will cause
 ** a panic.
 */
-static int RIOShortCommand(struct rio_info *p, struct Port *PortP,
+int RIOShortCommand(struct rio_info *p, struct Port *PortP,
 		int command, int len, int arg)
 {
 	PKT *PacketP;
diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232.c linux/drivers/char/ser_a2232.c
--- v2.4.6/linux/drivers/char/ser_a2232.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ser_a2232.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,880 @@
+/* drivers/char/ser_a2232.c */
+
+/* $Id: ser_a2232.c,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */
+
+/* Linux serial driver for the Amiga A2232 board */
+
+/* This driver is MAINTAINED. Before applying any changes, please contact
+ * the author.
+ */
+
+/* Copyright (c) 2000-2001 Enver Haase    <ehaase@inf.fu-berlin.de>
+ *                   alias The A2232 driver project <A2232@gmx.net>
+ * 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; 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.
+ *
+ */
+/***************************** Documentation ************************/
+/*
+ * This driver is in EXPERIMENTAL state. That means I could not find
+ * someone with five A2232 boards with 35 ports running at 19200 bps
+ * at the same time and test the machine's behaviour.
+ * However, I know that you can performance-tweak this driver (see
+ * the source code).
+ * One thing to consider is the time this driver consumes during the
+ * Amiga's vertical blank interrupt. Everything that is to be done
+ * _IS DONE_ when entering the vertical blank interrupt handler of
+ * this driver.
+ * However, it would be more sane to only do the job for only ONE card
+ * instead of ALL cards at a time; or, more generally, to handle only
+ * SOME ports instead of ALL ports at a time.
+ * However, as long as no-one runs into problems I guess I shouldn't
+ * change the driver as it runs fine for me :) .
+ *
+ * Version history of this file:
+ * 0.4	Resolved licensing issues.
+ * 0.3	Inclusion in the Linux/m68k tree, small fixes.
+ * 0.2	Added documentation, minor typo fixes.
+ * 0.1	Initial release.
+ *
+ * TO DO:
+ * -	Handle incoming BREAK events. I guess "Stevens: Advanced
+ *	Programming in the UNIX(R) Environment" is a good reference
+ *	on what is to be done.
+ * -	When installing as a module, don't simply 'printk' text, but
+ *	send it to the TTY used by the user.
+ *
+ * THANKS TO:
+ * -	Jukka Marin (65EC02 code).
+ * -	The other NetBSD developers on whose A2232 driver I had a
+ *	pretty close look. However, I didn't copy any code so it
+ *	is okay to put my code under the GPL and include it into
+ *	Linux.
+ */
+/***************************** End of Documentation *****************/
+
+/***************************** Defines ******************************/
+/*
+ * Enables experimental 115200 (normal) 230400 (turbo) baud rate.
+ * The A2232 specification states it can only operate at speeds up to
+ * 19200 bits per second, and I was not able to send a file via
+ * "sz"/"rz" and a null-modem cable from one A2232 port to another
+ * at 115200 bits per second.
+ * However, this might work for you.
+ */
+#undef A2232_SPEEDHACK
+/*
+ * Default is not to use RTS/CTS so you could be talked to death.
+ */
+#define A2232_SUPPRESS_RTSCTS_WARNING
+/************************* End of Defines ***************************/
+
+/***************************** Includes *****************************/
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/setup.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/semaphore.h>
+
+#include <linux/delay.h>
+
+#include <linux/serial.h>
+#include <linux/generic_serial.h>
+
+#include "ser_a2232.h"
+#include "ser_a2232fw.h"
+/************************* End of Includes **************************/
+
+/***************************** Prototypes ***************************/
+/* Helper functions */
+static __inline__ volatile struct a2232status *a2232stat(unsigned int board,
+						unsigned int portonboard);
+static __inline__ volatile struct a2232memory *a2232mem (unsigned int board); 
+static __inline__ void a2232_receive_char(	struct a2232_port *port,
+						int ch, int err );
+/* The interrupt service routine */
+static void a2232_vbl_inter(int irq, void *data, struct pt_regs *fp);
+/* Initialize the port structures */
+static void a2232_init_portstructs(void);
+/* Initialize and register TTY drivers. */
+/* returns 0 IFF successful */
+static int a2232_init_drivers(void); 
+/* Initialize all A2232 boards; main entry point. */
+int a2232board_init(void);
+
+/* BEGIN GENERIC_SERIAL PROTOTYPES */
+static void a2232_disable_tx_interrupts(void *ptr);
+static void a2232_enable_tx_interrupts(void *ptr);
+static void a2232_disable_rx_interrupts(void *ptr);
+static void a2232_enable_rx_interrupts(void *ptr);
+static int  a2232_get_CD(void *ptr);
+static void a2232_shutdown_port(void *ptr);
+static int  a2232_set_real_termios(void *ptr);
+static int  a2232_chars_in_buffer(void *ptr);
+static void a2232_close(void *ptr);
+static void a2232_hungup(void *ptr);
+/* static void a2232_getserial (void *ptr, struct serial_struct *sp); */
+/* END GENERIC_SERIAL PROTOTYPES */
+
+/* Functions that the TTY driver struct expects */
+static int  a2232_ioctl(struct tty_struct *tty, struct file *file,
+										unsigned int cmd, unsigned long arg);
+static void a2232_throttle(struct tty_struct *tty);
+static void a2232_unthrottle(struct tty_struct *tty);
+static int  a2232_open(struct tty_struct * tty, struct file * filp);
+/************************* End of Prototypes ************************/
+
+/***************************** Global variables *********************/
+/*---------------------------------------------------------------------------
+ * Interface from generic_serial.c back here
+ *--------------------------------------------------------------------------*/
+static struct real_driver a2232_real_driver = {
+        a2232_disable_tx_interrupts,
+        a2232_enable_tx_interrupts,
+        a2232_disable_rx_interrupts,
+        a2232_enable_rx_interrupts,
+        a2232_get_CD,
+        a2232_shutdown_port,
+        a2232_set_real_termios,
+        a2232_chars_in_buffer,
+        a2232_close,
+        a2232_hungup,
+	NULL	/* a2232_getserial */
+};
+
+static void *a2232_driver_ID = &a2232_driver_ID; // Some memory address WE own.
+
+/* Ports structs */
+static struct a2232_port a2232_ports[MAX_A2232_BOARDS*NUMLINES];
+
+/* TTY driver structs */
+static struct tty_driver a2232_driver;
+static struct tty_driver a2232_callout_driver;
+
+/* Variables used by the TTY driver */
+static int a2232_refcount;
+static struct tty_struct *a2232_table[MAX_A2232_BOARDS*NUMLINES] = { NULL, };
+static struct termios *a2232_termios[MAX_A2232_BOARDS*NUMLINES];
+static struct termios *a2232_termios_locked[MAX_A2232_BOARDS*NUMLINES];
+
+/* nr of cards completely (all ports) and correctly configured */
+static int nr_a2232; 
+
+/* zorro_dev structs for the A2232's */
+static struct zorro_dev *zd_a2232[MAX_A2232_BOARDS]; 
+/***************************** End of Global variables **************/
+
+/***************************** Functions ****************************/
+/*** BEGIN OF REAL_DRIVER FUNCTIONS ***/
+
+static void a2232_disable_tx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *stat;
+	unsigned long flags;
+  
+	port = ptr;
+	stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
+	stat->OutDisable = -1;
+
+	/* Does this here really have to be? */
+	save_flags(flags);
+	cli(); 
+	port->gs.flags &= ~GS_TX_INTEN;
+	restore_flags(flags);
+}
+
+static void a2232_enable_tx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *stat;
+	unsigned long flags;
+
+	port = ptr;
+	stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
+	stat->OutDisable = 0;
+
+	/* Does this here really have to be? */
+	save_flags(flags);
+	cli();
+	port->gs.flags |= GS_TX_INTEN;
+	restore_flags(flags);
+}
+
+static void a2232_disable_rx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	port = ptr;
+	port->disable_rx = -1;
+}
+
+static void a2232_enable_rx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	port = ptr;
+	port->disable_rx = 0;
+}
+
+static int  a2232_get_CD(void *ptr)
+{
+	return ((struct a2232_port *) ptr)->cd_status;
+}
+
+static void a2232_shutdown_port(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *stat;
+	unsigned long flags;
+
+	port = ptr;
+	stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
+
+	save_flags(flags);
+	cli();
+
+	port->gs.flags &= ~GS_ACTIVE;
+	
+	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
+		/* Set DTR and RTS to Low, flush output.
+		   The NetBSD driver "msc.c" does it this way. */
+		stat->Command = (	(stat->Command & ~A2232CMD_CMask) | 
+					A2232CMD_Close );
+		stat->OutFlush = -1;
+		stat->Setup = -1;
+	}
+
+	restore_flags(flags);
+	
+	/* After analyzing control flow, I think a2232_shutdown_port
+		is actually the last call from the system when at application
+		level someone issues a "echo Hello >>/dev/ttyY0".
+		Therefore I think the MOD_DEC_USE_COUNT should be here and
+		not in "a2232_close()". See the comment in "sx.c", too.
+		If you run into problems, compile this driver into the
+		kernel instead of compiling it as a module. */
+	MOD_DEC_USE_COUNT;
+}
+
+static int  a2232_set_real_termios(void *ptr)
+{
+	unsigned int cflag, baud, chsize, stopb, parity, softflow;
+	int rate;
+	int a2232_param, a2232_cmd;
+	unsigned long flags;
+	unsigned int i;
+	struct a2232_port *port = ptr;
+	volatile struct a2232status *status;
+	volatile struct a2232memory *mem;
+
+	if (!port->gs.tty || !port->gs.tty->termios) return 0;
+
+	status = a2232stat(port->which_a2232, port->which_port_on_a2232);
+	mem = a2232mem(port->which_a2232);
+	
+	a2232_param = a2232_cmd = 0;
+
+	// get baud rate
+	baud = port->gs.baud;
+	if (baud == 0) {
+		/* speed == 0 -> drop DTR, do nothing else */
+		save_flags(flags);
+		cli();
+		// Clear DTR (and RTS... mhhh).
+		status->Command = (	(status->Command & ~A2232CMD_CMask) |
+					A2232CMD_Close );
+		status->OutFlush = -1;
+		status->Setup = -1;
+		
+		restore_flags(flags);
+		return 0;
+	}
+	
+	rate = A2232_BAUD_TABLE_NOAVAIL;
+	for (i=0; i < A2232_BAUD_TABLE_NUM_RATES * 3; i += 3){
+		if (a2232_baud_table[i] == baud){
+			if (mem->Common.Crystal == A2232_TURBO) rate = a2232_baud_table[i+2];
+			else                                    rate = a2232_baud_table[i+1];
+		}
+	}
+	if (rate == A2232_BAUD_TABLE_NOAVAIL){
+		printk("a2232: Board %d Port %d unsupported baud rate: %d baud. Using another.\n",port->which_a2232,port->which_port_on_a2232,baud);
+		// This is useful for both (turbo or normal) Crystal versions.
+		rate = A2232PARAM_B9600;
+	}
+	a2232_param |= rate;
+
+	cflag  = port->gs.tty->termios->c_cflag;
+
+	// get character size
+	chsize = cflag & CSIZE;
+	switch (chsize){
+		case CS8: 	a2232_param |= A2232PARAM_8Bit; break;
+		case CS7: 	a2232_param |= A2232PARAM_7Bit; break;
+		case CS6: 	a2232_param |= A2232PARAM_6Bit; break;
+		case CS5: 	a2232_param |= A2232PARAM_5Bit; break;
+		default:	printk("a2232: Board %d Port %d unsupported character size: %d. Using 8 data bits.\n",
+					port->which_a2232,port->which_port_on_a2232,chsize);
+				a2232_param |= A2232PARAM_8Bit; break;
+	}
+
+	// get number of stop bits
+	stopb  = cflag & CSTOPB;
+	if (stopb){ // two stop bits instead of one
+		printk("a2232: Board %d Port %d 2 stop bits unsupported. Using 1 stop bit.\n",
+			port->which_a2232,port->which_port_on_a2232);
+	}
+
+	// Warn if RTS/CTS not wanted
+	if (!(cflag & CRTSCTS)){
+#ifndef A2232_SUPPRESS_RTSCTS_WARNING
+		printk("a2232: Board %d Port %d cannot switch off firmware-implemented RTS/CTS hardware flow control.\n",
+			port->which_a2232,port->which_port_on_a2232);
+#endif
+	}
+
+	/*	I think this is correct.
+		However, IXOFF means _input_ flow control and I wonder
+		if one should care about IXON _output_ flow control,
+		too. If this makes problems, one should turn the A2232
+		firmware XON/XOFF "SoftFlow" flow control off and use
+		the conventional way of inserting START/STOP characters
+		by hand in throttle()/unthrottle().
+	*/
+	softflow = !!( port->gs.tty->termios->c_iflag & IXOFF );
+
+	// get Parity (Enabled/Disabled? If Enabled, Odd or Even?)
+	parity = cflag & (PARENB | PARODD);
+	if (parity & PARENB){
+		if (parity & PARODD){
+			a2232_cmd |= A2232CMD_OddParity;
+		}
+		else{
+			a2232_cmd |= A2232CMD_EvenParity;
+		}
+	}
+	else a2232_cmd |= A2232CMD_NoParity;
+
+
+	/*	Hmm. Maybe an own a2232_port structure
+		member would be cleaner?	*/
+	if (cflag & CLOCAL)
+		port->gs.flags &= ~ASYNC_CHECK_CD;
+	else
+		port->gs.flags |= ASYNC_CHECK_CD;
+
+
+	/* Now we have all parameters and can go to set them: */
+	save_flags(flags);
+	cli();
+
+	status->Param = a2232_param | A2232PARAM_RcvBaud;
+	status->Command = a2232_cmd | A2232CMD_Open |  A2232CMD_Enable;
+	status->SoftFlow = softflow;
+	status->OutDisable = 0;
+	status->Setup = -1;
+
+	restore_flags(flags);
+	return 0;
+}
+
+static int  a2232_chars_in_buffer(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *status; 
+	unsigned char ret; /* we need modulo-256 arithmetics */
+	port = ptr;
+	status = a2232stat(port->which_a2232, port->which_port_on_a2232);
+#if A2232_IOBUFLEN != 256
+#error "Re-Implement a2232_chars_in_buffer()!"
+#endif
+	ret = (status->OutHead - status->OutTail);
+	return ret;
+}
+
+static void a2232_close(void *ptr)
+{
+	a2232_disable_tx_interrupts(ptr);
+	a2232_disable_rx_interrupts(ptr);
+	/* see the comment in a2232_shutdown_port above. */
+	/* MOD_DEC_USE_COUNT; */
+}
+
+static void a2232_hungup(void *ptr)
+{
+	a2232_close(ptr);
+}
+/*** END   OF REAL_DRIVER FUNCTIONS ***/
+
+/*** BEGIN  FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/
+static int a2232_ioctl(	struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+static void a2232_throttle(struct tty_struct *tty)
+{
+/* Throttle: System cannot take another chars: Drop RTS or
+             send the STOP char or whatever.
+   The A2232 firmware does RTS/CTS anyway, and XON/XOFF
+   if switched on. So the only thing we can do at this
+   layer here is not taking any characters out of the
+   A2232 buffer any more. */
+	struct a2232_port *port = (struct a2232_port *) tty->driver_data;
+	port->throttle_input = -1;
+}
+
+static void a2232_unthrottle(struct tty_struct *tty)
+{
+/* Unthrottle: dual to "throttle()" above. */
+	struct a2232_port *port = (struct a2232_port *) tty->driver_data;
+	port->throttle_input = 0;
+}
+
+static int  a2232_open(struct tty_struct * tty, struct file * filp)
+{
+/* More or less stolen from other drivers. */
+	int line;
+	int retval;
+	struct a2232_port *port;
+
+	line = MINOR(tty->device);
+	port = &a2232_ports[line];
+	
+	tty->driver_data = port;
+	port->gs.tty = tty;
+	port->gs.count++;
+	retval = gs_init_port(&port->gs);
+	if (retval) {
+		port->gs.count--;
+		return retval;
+	}
+	port->gs.flags |= GS_ACTIVE;
+	if (port->gs.count == 1) {
+		MOD_INC_USE_COUNT;
+	}
+	retval = gs_block_til_ready(port, filp);
+
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		port->gs.count--;
+		return retval;
+	}
+
+	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)){
+		if (tty->driver.subtype == A2232_TTY_SUBTYPE_NORMAL)
+			*tty->termios = port->gs.normal_termios;
+		else 
+			*tty->termios = port->gs.callout_termios;
+		a2232_set_real_termios (port);
+	}
+
+	port->gs.session = current->session;
+	port->gs.pgrp = current->pgrp;
+
+	a2232_enable_rx_interrupts(port);
+	
+	return 0;
+}
+/*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/
+
+static __inline__ volatile struct a2232status *a2232stat(unsigned int board, unsigned int portonboard)
+{
+	volatile struct a2232memory *mem = a2232mem(board);
+	return &(mem->Status[portonboard]);
+}
+
+static __inline__ volatile struct a2232memory *a2232mem (unsigned int board)
+{
+	return (volatile struct a2232memory *) ZTWO_VADDR( zd_a2232[board]->resource.start );
+}
+
+static __inline__ void a2232_receive_char(	struct a2232_port *port,
+						int ch, int err )
+{
+/* 	Mostly stolen from other drivers.
+	Maybe one could implement a more efficient version by not only
+	transferring one character at a time.
+*/
+	struct tty_struct *tty = port->gs.tty;
+	
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+		return;
+
+	tty->flip.count++;
+
+#if 0
+	switch(err) {
+	case TTY_BREAK:
+		break;
+	case TTY_PARITY:
+		break;
+	case TTY_OVERRUN:
+		break;
+	case TTY_FRAME:
+		break;
+	}
+#endif
+
+	*tty->flip.flag_buf_ptr++ = err;
+	*tty->flip.char_buf_ptr++ = ch;
+	tty_flip_buffer_push(tty);
+}
+
+static void a2232_vbl_inter(int irq, void *data, struct pt_regs *fp)
+{
+#if A2232_IOBUFLEN != 256
+#error "Re-Implement a2232_vbl_inter()!"
+#endif
+
+struct a2232_port *port;
+volatile struct a2232memory *mem;
+volatile struct a2232status *status;
+unsigned char newhead;
+unsigned char bufpos; /* Must be unsigned char. We need the modulo-256 arithmetics */
+unsigned char ncd, ocd, ccd; /* names consistent with the NetBSD driver */
+volatile u_char *ibuf, *cbuf, *obuf;
+int ch, err, n, p;
+	for (n = 0; n < nr_a2232; n++){		/* for every completely initialized A2232 board */
+		mem = a2232mem(n);
+		for (p = 0; p < NUMLINES; p++){	/* for every port on this board */
+			err = 0;
+			port = &a2232_ports[n*NUMLINES+p];
+			if ( port->gs.flags & GS_ACTIVE ){ /* if the port is used */
+
+				status = a2232stat(n,p);
+
+				if (!port->disable_rx && !port->throttle_input){ /* If input is not disabled */
+					newhead = status->InHead;               /* 65EC02 write pointer */
+					bufpos = status->InTail;
+
+					/* check for input for this port */
+					if (newhead != bufpos) {
+						/* buffer for input chars/events */
+						ibuf = mem->InBuf[p];
+ 
+						/* data types of bytes in ibuf */
+						cbuf = mem->InCtl[p];
+ 
+						/* do for all chars */
+						while (bufpos != newhead) {
+							/* which type of input data? */
+							switch (cbuf[bufpos]) {
+								/* switch on input event (CD, BREAK, etc.) */
+							case A2232INCTL_EVENT:
+								switch (ibuf[bufpos++]) {
+								case A2232EVENT_Break:
+									/* TODO: Handle BREAK signal */
+									break;
+									/*	A2232EVENT_CarrierOn and A2232EVENT_CarrierOff are
+										handled in a separate queue and should not occur here. */
+								case A2232EVENT_Sync:
+									printk("A2232: 65EC02 software sent SYNC event, don't know what to do. Ignoring.");
+									break;
+								default:
+									printk("A2232: 65EC02 software broken, unknown event type %d occured.\n",ibuf[bufpos-1]);
+								} /* event type switch */
+								break;
+ 							case A2232INCTL_CHAR:
+								/* Receive incoming char */
+								a2232_receive_char(port, ibuf[bufpos], err);
+								bufpos++;
+								break;
+ 							default:
+								printk("A2232: 65EC02 software broken, unknown data type %d occured.\n",cbuf[bufpos]);
+								bufpos++;
+							} /* switch on input data type */
+						} /* while there's something in the buffer */
+
+						status->InTail = bufpos;            /* tell 65EC02 what we've read */
+						
+					} /* if there was something in the buffer */                          
+				} /* If input is not disabled */
+
+				/* Now check if there's something to output */
+				obuf = mem->OutBuf[p];
+				bufpos = status->OutHead;
+				while ( (port->gs.xmit_cnt > 0)		&&
+					(!port->gs.tty->stopped)	&&
+					(!port->gs.tty->hw_stopped) ){	/* While there are chars to transmit */
+					if (((bufpos+1) & A2232_IOBUFLENMASK) != status->OutTail) { /* If the A2232 buffer is not full */
+						ch = port->gs.xmit_buf[port->gs.xmit_tail];					/* get the next char to transmit */
+						port->gs.xmit_tail = (port->gs.xmit_tail+1) & (SERIAL_XMIT_SIZE-1); /* modulo-addition for the gs.xmit_buf ring-buffer */
+						obuf[bufpos++] = ch;																/* put it into the A2232 buffer */
+						port->gs.xmit_cnt--;
+					}
+					else{																									/* If A2232 the buffer is full */
+						break;																							/* simply stop filling it. */
+					}													
+				}					
+				status->OutHead = bufpos;
+					
+				/* WakeUp if output buffer runs low */
+				if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
+					if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){
+						(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+					}
+					wake_up_interruptible(&port->gs.tty->write_wait);
+				}
+			} // if the port is used
+		} // for every port on the board
+			
+		/* Now check the CD message queue */
+		newhead = mem->Common.CDHead;
+		bufpos = mem->Common.CDTail;
+		if (newhead != bufpos){				/* There are CD events in queue */
+			ocd = mem->Common.CDStatus; 		/* get old status bits */
+			while (newhead != bufpos){		/* read all events */
+				ncd = mem->CDBuf[bufpos++]; 	/* get one event */
+				ccd = ncd ^ ocd; 		/* mask of changed lines */
+				ocd = ncd; 			/* save new status bits */
+				for(p=0; p < NUMLINES; p++){	/* for all ports */
+					if (ccd & 1){		/* this one changed */
+
+						struct a2232_port *port = &a2232_ports[n*7+p];
+						port->cd_status = !(ncd & 1); /* ncd&1 <=> CD is now off */
+
+						if (!(port->gs.flags & ASYNC_CHECK_CD))
+							;	/* Don't report DCD changes */
+						else if (port->cd_status) { // if DCD on: DCD went UP!
+							if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) ||
+							    ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) {
+								/* Are we blocking in open?*/
+								wake_up_interruptible(&port->gs.open_wait);
+							}
+						}
+						else { // if DCD off: DCD went DOWN!
+							if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
+							      (port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
+								if (port->gs.tty)
+									tty_hangup (port->gs.tty);
+							}
+						}
+						
+					} // if CD changed for this port
+					ccd >>= 1;
+					ncd >>= 1;									/* Shift bits for next line */
+				} // for every port
+			} // while CD events in queue
+			mem->Common.CDStatus = ocd; /* save new status */
+			mem->Common.CDTail = bufpos; /* remove events */
+		} // if events in CD queue
+		
+	} // for every completely initialized A2232 board
+}
+
+static void a2232_init_portstructs(void)
+{
+	struct a2232_port *port;
+	int i;
+
+	for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) {
+		port = a2232_ports + i;
+		port->which_a2232 = i/NUMLINES;
+		port->which_port_on_a2232 = i%NUMLINES;
+		port->disable_rx = port->throttle_input = port->cd_status = 0;
+		port->gs.callout_termios = tty_std_termios;
+		port->gs.normal_termios = tty_std_termios;
+		port->gs.magic = A2232_MAGIC;
+		port->gs.close_delay = HZ/2;
+		port->gs.closing_wait = 30 * HZ;
+		port->gs.rd = &a2232_real_driver;
+#ifdef NEW_WRITE_LOCKING
+		init_MUTEX(&(port->gs.port_write_sem));
+#endif
+		init_waitqueue_head(&port->gs.open_wait);
+		init_waitqueue_head(&port->gs.close_wait);
+	}
+}
+
+static int a2232_init_drivers(void)
+{
+	int error;
+
+	memset(&a2232_driver, 0, sizeof(a2232_driver));
+	a2232_driver.magic = TTY_DRIVER_MAGIC;
+	a2232_driver.driver_name = "commodore_a2232";
+	a2232_driver.name = "ttyY";
+	a2232_driver.major = A2232_NORMAL_MAJOR;
+	a2232_driver.num = NUMLINES * nr_a2232;
+	a2232_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	a2232_driver.subtype = A2232_TTY_SUBTYPE_NORMAL;
+	a2232_driver.init_termios = tty_std_termios;
+	a2232_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	a2232_driver.flags = TTY_DRIVER_REAL_RAW;
+	a2232_driver.refcount = &a2232_refcount;
+	a2232_driver.table = a2232_table;
+	a2232_driver.termios = a2232_termios;
+	a2232_driver.termios_locked = a2232_termios_locked;
+
+	a2232_driver.open = a2232_open;
+	a2232_driver.close = gs_close;
+	a2232_driver.write = gs_write;
+	a2232_driver.put_char = gs_put_char;
+	a2232_driver.flush_chars = gs_flush_chars;
+	a2232_driver.write_room = gs_write_room;
+	a2232_driver.chars_in_buffer = gs_chars_in_buffer;
+	a2232_driver.flush_buffer = gs_flush_buffer;
+	a2232_driver.ioctl = a2232_ioctl;
+	a2232_driver.throttle = a2232_throttle;
+	a2232_driver.unthrottle = a2232_unthrottle;
+	a2232_driver.set_termios = gs_set_termios;
+	a2232_driver.stop = gs_stop;
+	a2232_driver.start = gs_start;
+	a2232_driver.hangup = gs_hangup;
+
+	a2232_callout_driver = a2232_driver;
+	a2232_callout_driver.name = "cuy";
+	a2232_callout_driver.major = A2232_CALLOUT_MAJOR;
+	a2232_callout_driver.subtype = A2232_TTY_SUBTYPE_CALLOUT;
+
+	if ((error = tty_register_driver(&a2232_driver))) {
+		printk(KERN_ERR "A2232: Couldn't register A2232 driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	if ((error = tty_register_driver(&a2232_callout_driver))) {
+		tty_unregister_driver(&a2232_driver);
+		printk(KERN_ERR "A2232: Couldn't register A2232 callout driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	return 0;
+}
+
+int a2232board_init(void)
+{
+	struct zorro_dev *z;
+
+	unsigned int boardaddr;
+	int bcount;
+	short start;
+	u_char *from;
+	volatile u_char *to;
+	volatile struct a2232memory *mem;
+
+#ifdef __SMP__
+	return -ENODEV;	/* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */
+#endif
+
+	if (!MACH_IS_AMIGA){
+		return -ENODEV;
+	}
+
+	printk("Commodore A2232 driver initializing.\n"); /* Say that we're alive. */
+
+	z = NULL;
+	nr_a2232 = 0;
+	while ( (z = zorro_find_device(ZORRO_WILDCARD, z)) ){
+		if (	(z->id != ZORRO_PROD_CBM_A2232_PROTOTYPE) && 
+			(z->id != ZORRO_PROD_CBM_A2232)	){
+			continue;	// The board found was no A2232
+		}
+		if (!zorro_request_device(z,"A2232 driver"))
+			continue;
+
+		printk("Commodore A2232 found (#%d).\n",nr_a2232);
+
+		zd_a2232[nr_a2232] = z;
+
+		boardaddr = ZTWO_VADDR( z->resource.start );
+		printk("Board is located at address 0x%x, size is 0x%x.\n", boardaddr, (unsigned int) ((z->resource.end+1) - (z->resource.start)));
+
+		mem = (volatile struct a2232memory *) boardaddr;
+
+		(void) mem->Enable6502Reset;   /* copy the code across to the board */
+		to = (u_char *)mem;  from = a2232_65EC02code; bcount = sizeof(a2232_65EC02code) - 2;
+		start = *(short *)from;
+		from += sizeof(start);
+		to += start;
+		while(bcount--) *to++ = *from++;
+		printk("65EC02 software uploaded to the A2232 memory.\n");
+  
+		mem->Common.Crystal = A2232_UNKNOWN;  /* use automatic speed check */
+  
+		/* start 6502 running */
+		(void) mem->ResetBoard;
+		printk("A2232's 65EC02 CPU up and running.\n");
+  
+		/* wait until speed detector has finished */
+		for (bcount = 0; bcount < 2000; bcount++) {
+			udelay(1000);
+			if (mem->Common.Crystal)
+				break;
+		}
+		printk((mem->Common.Crystal?"A2232 oscillator crystal detected by 65EC02 software: ":"65EC02 software could not determine A2232 oscillator crystal: "));
+		switch (mem->Common.Crystal){
+		case A2232_UNKNOWN:
+			printk("Unknown crystal.\n");
+			break;
+ 		case A2232_NORMAL:
+			printk ("Normal crystal.\n");
+			break;
+		case A2232_TURBO:
+			printk ("Turbo crystal.\n");
+			break;
+		default:
+			printk ("0x%x. Huh?\n",mem->Common.Crystal);
+		}
+
+		nr_a2232++;
+
+	}	
+
+	printk("Total: %d A2232 boards initialized.\n.", nr_a2232); /* Some status report if no card was found */
+
+	a2232_init_portstructs();
+
+	/*
+		a2232_init_drivers also registers the drivers. Must be here because all boards
+		have to be detected first.
+	*/
+	if (a2232_init_drivers()) return -ENODEV; // maybe we should use a different -Exxx?
+
+	request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0, "A2232 serial VBL", a2232_driver_ID);
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return a2232board_init();
+}
+
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0; i < nr_a2232; i++) {
+		zorro_release_device(zd_a2232[i]);
+	}
+
+	tty_unregister_driver(&a2232_driver);
+	tty_unregister_driver(&a2232_callout_driver);
+	free_irq(IRQ_AMIGA_VERTB, a2232_driver_ID);
+}
+#endif
+/***************************** End of Functions *********************/
diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232.h linux/drivers/char/ser_a2232.h
--- v2.4.6/linux/drivers/char/ser_a2232.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ser_a2232.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,206 @@
+/* drivers/char/ser_a2232.h */
+
+/* $Id: ser_a2232.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */
+
+/* Linux serial driver for the Amiga A2232 board */
+
+/* This driver is MAINTAINED. Before applying any changes, please contact
+ * the author.
+ */
+   
+/* Copyright (c) 2000-2001 Enver Haase    <ehaase@inf.fu-berlin.de>
+ *                   alias The A2232 driver project <A2232@gmx.net>
+ * 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; 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 _SER_A2232_H_
+#define _SER_A2232_H_
+
+/*
+	How many boards are to be supported at maximum;
+	"up to five A2232 Multiport Serial Cards may be installed in a
+	single Amiga 2000" states the A2232 User's Guide. If you have
+	more slots available, you might want to change the value below.
+*/
+#define MAX_A2232_BOARDS 5
+
+#ifndef A2232_NORMAL_MAJOR
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define A2232_NORMAL_MAJOR  224	/* /dev/ttyY* */
+#define A2232_CALLOUT_MAJOR 225	/* /dev/cuy*  */
+#endif
+
+/* Some magic is always good - Who knows :) */
+#define A2232_MAGIC 0x000a2232
+
+/* for the tty_struct subtype field */
+#define A2232_TTY_SUBTYPE_NORMAL	1
+#define A2232_TTY_SUBTYPE_CALLOUT	2
+
+/* A2232 port structure to keep track of the
+   status of every single line used */
+struct a2232_port{
+	struct gs_port gs;
+	unsigned int which_a2232;
+	unsigned int which_port_on_a2232;
+	short disable_rx;
+	short throttle_input;
+	short cd_status;
+};
+
+#define	NUMLINES		7	/* number of lines per board */
+#define	A2232_IOBUFLEN		256	/* number of bytes per buffer */
+#define	A2232_IOBUFLENMASK	0xff	/* mask for maximum number of bytes */
+
+
+#define	A2232_UNKNOWN	0	/* crystal not known */
+#define	A2232_NORMAL	1	/* normal A2232 (1.8432 MHz oscillator) */
+#define	A2232_TURBO	2	/* turbo A2232 (3.6864 MHz oscillator) */
+
+
+struct a2232common {
+	char   Crystal;	/* normal (1) or turbo (2) board? */
+	u_char Pad_a;
+	u_char TimerH;	/* timer value after speed check */
+	u_char TimerL;
+	u_char CDHead;	/* head pointer for CD message queue */
+	u_char CDTail;	/* tail pointer for CD message queue */
+	u_char CDStatus;
+	u_char Pad_b;
+};
+
+struct a2232status {
+	u_char InHead;		/* input queue head */
+	u_char InTail;		/* input queue tail */
+	u_char OutDisable;	/* disables output */
+	u_char OutHead;		/* output queue head */
+	u_char OutTail;		/* output queue tail */
+	u_char OutCtrl;		/* soft flow control character to send */
+	u_char OutFlush;	/* flushes output buffer */
+	u_char Setup;		/* causes reconfiguration */
+	u_char Param;		/* parameter byte - see A2232PARAM */
+	u_char Command;		/* command byte - see A2232CMD */
+	u_char SoftFlow;	/* enables xon/xoff flow control */
+	/* private 65EC02 fields: */
+	u_char XonOff;		/* stores XON/XOFF enable/disable */
+};
+
+#define	A2232_MEMPAD1	\
+	(0x0200 - NUMLINES * sizeof(struct a2232status)	-	\
+	sizeof(struct a2232common))
+#define	A2232_MEMPAD2	(0x2000 - NUMLINES * A2232_IOBUFLEN - A2232_IOBUFLEN)
+
+struct a2232memory {
+	struct a2232status Status[NUMLINES];	/* 0x0000-0x006f status areas */
+	struct a2232common Common;		/* 0x0070-0x0077 common flags */
+	u_char Dummy1[A2232_MEMPAD1];		/* 0x00XX-0x01ff */
+	u_char OutBuf[NUMLINES][A2232_IOBUFLEN];/* 0x0200-0x08ff output bufs */
+	u_char InBuf[NUMLINES][A2232_IOBUFLEN];	/* 0x0900-0x0fff input bufs */
+	u_char InCtl[NUMLINES][A2232_IOBUFLEN];	/* 0x1000-0x16ff control data */
+	u_char CDBuf[A2232_IOBUFLEN];		/* 0x1700-0x17ff CD event buffer */
+	u_char Dummy2[A2232_MEMPAD2];		/* 0x1800-0x2fff */
+	u_char Code[0x1000];			/* 0x3000-0x3fff code area */
+	u_short InterruptAck;			/* 0x4000        intr ack */
+	u_char Dummy3[0x3ffe];			/* 0x4002-0x7fff */
+	u_short Enable6502Reset;		/* 0x8000 Stop board, */
+						/*  6502 RESET line held low */
+	u_char Dummy4[0x3ffe];			/* 0x8002-0xbfff */
+	u_short ResetBoard;			/* 0xc000 reset board & run, */
+						/*  6502 RESET line held high */
+};
+
+#undef A2232_MEMPAD1
+#undef A2232_MEMPAD2
+
+#define	A2232INCTL_CHAR		0	/* corresponding byte in InBuf is a character */
+#define	A2232INCTL_EVENT	1	/* corresponding byte in InBuf is an event */
+
+#define	A2232EVENT_Break	1	/* break set */
+#define	A2232EVENT_CarrierOn	2	/* carrier raised */
+#define	A2232EVENT_CarrierOff	3	/* carrier dropped */
+#define A2232EVENT_Sync		4	/* don't know, defined in 2232.ax */
+
+#define	A2232CMD_Enable		0x1	/* enable/DTR bit */
+#define	A2232CMD_Close		0x2	/* close the device */
+#define	A2232CMD_Open		0xb	/* open the device */
+#define	A2232CMD_CMask		0xf	/* command mask */
+#define	A2232CMD_RTSOff		0x0  	/* turn off RTS */
+#define	A2232CMD_RTSOn		0x8	/* turn on RTS */
+#define	A2232CMD_Break		0xd	/* transmit a break */
+#define	A2232CMD_RTSMask	0xc	/* mask for RTS stuff */
+#define	A2232CMD_NoParity	0x00	/* don't use parity */
+#define	A2232CMD_OddParity	0x20	/* odd parity */
+#define	A2232CMD_EvenParity	0x60	/* even parity */
+#define	A2232CMD_ParityMask	0xe0	/* parity mask */
+
+#define	A2232PARAM_B115200	0x0	/* baud rates */
+#define	A2232PARAM_B50		0x1
+#define	A2232PARAM_B75		0x2
+#define	A2232PARAM_B110		0x3
+#define	A2232PARAM_B134		0x4
+#define	A2232PARAM_B150		0x5
+#define	A2232PARAM_B300		0x6
+#define	A2232PARAM_B600		0x7
+#define	A2232PARAM_B1200	0x8
+#define	A2232PARAM_B1800	0x9
+#define	A2232PARAM_B2400	0xa
+#define	A2232PARAM_B3600	0xb
+#define	A2232PARAM_B4800	0xc
+#define	A2232PARAM_B7200	0xd
+#define	A2232PARAM_B9600	0xe
+#define	A2232PARAM_B19200	0xf
+#define	A2232PARAM_BaudMask	0xf	/* baud rate mask */
+#define	A2232PARAM_RcvBaud	0x10	/* enable receive baud rate */
+#define	A2232PARAM_8Bit		0x00	/* numbers of bits */
+#define	A2232PARAM_7Bit		0x20
+#define	A2232PARAM_6Bit		0x40
+#define	A2232PARAM_5Bit		0x60
+#define	A2232PARAM_BitMask	0x60	/* numbers of bits mask */
+
+
+/* Standard speeds tables, -1 means unavailable, -2 means 0 baud: switch off line */
+#define A2232_BAUD_TABLE_NOAVAIL -1
+#define A2232_BAUD_TABLE_NUM_RATES (18)
+static int a2232_baud_table[A2232_BAUD_TABLE_NUM_RATES*3] = {
+	//Baud	//Normal			//Turbo
+	50,	A2232PARAM_B50,			A2232_BAUD_TABLE_NOAVAIL,
+	75,	A2232PARAM_B75,			A2232_BAUD_TABLE_NOAVAIL,
+	110,	A2232PARAM_B110,		A2232_BAUD_TABLE_NOAVAIL,
+	134,	A2232PARAM_B134,		A2232_BAUD_TABLE_NOAVAIL,
+	150,	A2232PARAM_B150,		A2232PARAM_B75,
+	200,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL,
+	300,	A2232PARAM_B300,		A2232PARAM_B150,
+	600,	A2232PARAM_B600,		A2232PARAM_B300,
+	1200,	A2232PARAM_B1200,		A2232PARAM_B600,
+	1800,	A2232PARAM_B1800,		A2232_BAUD_TABLE_NOAVAIL,
+	2400,	A2232PARAM_B2400,		A2232PARAM_B1200,
+	4800,	A2232PARAM_B4800,		A2232PARAM_B2400,
+	9600,	A2232PARAM_B9600,		A2232PARAM_B4800,
+	19200,	A2232PARAM_B19200,		A2232PARAM_B9600,
+	38400,	A2232_BAUD_TABLE_NOAVAIL,	A2232PARAM_B19200,
+	57600,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL,
+#ifdef A2232_SPEEDHACK
+	115200,	A2232PARAM_B115200,		A2232_BAUD_TABLE_NOAVAIL,
+	230400,	A2232_BAUD_TABLE_NOAVAIL,	A2232PARAM_B115200
+#else
+	115200,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL,
+	230400,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL
+#endif
+};
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232fw.ax linux/drivers/char/ser_a2232fw.ax
--- v2.4.6/linux/drivers/char/ser_a2232fw.ax	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ser_a2232fw.ax	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,529 @@
+;.lib "axm"
+;
+;begin
+;title "A2232 serial board driver"
+;
+;set modules "2232"
+;set executable "2232.bin"
+;
+;;;;set nolink
+;
+;set temporary directory "t:"
+;
+;set assembly options "-m6502 -l60:t:list"
+;set link options "bin"; loadadr"
+;;;bin2c 2232.bin msc6502.h msc6502code
+;end
+;
+;
+; ### Commodore A2232 serial board driver for NetBSD by JM v1.3 ###
+;
+; - Created 950501 by JM -
+;
+;
+; Serial board driver software.
+;
+;
+% Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>.
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions
+% are met:
+% 1. Redistributions of source code must retain the above copyright
+%    notice, and the entire permission notice in its entirety,
+%    including the disclaimer of warranties.
+% 2. Redistributions in binary form must reproduce the above copyright
+%    notice, this list of conditions and the following disclaimer in the
+%    documentation and/or other materials provided with the distribution.
+% 3. The name of the author may not be used to endorse or promote
+%    products derived from this software without specific prior
+%    written permission.
+%
+% ALTERNATIVELY, this product may be distributed under the terms of
+% the GNU General Public License, in which case the provisions of the
+% GPL are required INSTEAD OF the above restrictions.  (This clause is
+% necessary due to a potential bad interaction between the GPL and
+% the restrictions contained in a BSD-style copyright.)
+%
+% THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+% WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+% OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+% DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+% INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+% (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+% OF THE POSSIBILITY OF SUCH DAMAGE.
+;
+;
+; Bugs:
+;
+; - Can't send a break yet
+;
+;
+;
+; Edited:
+;
+; - 950501 by JM -> v0.1	- Created this file.
+; - 951029 by JM -> v1.3	- Carrier Detect events now queued in a separate
+;				  queue.
+;
+;
+
+
+CODE		equ	$3800		; start address for program code
+
+
+CTL_CHAR	equ	$00		; byte in ibuf is a character
+CTL_EVENT	equ	$01		; byte in ibuf is an event
+
+EVENT_BREAK	equ	$01
+EVENT_CDON	equ	$02
+EVENT_CDOFF	equ	$03
+EVENT_SYNC	equ	$04
+
+XON		equ	$11
+XOFF		equ	$13
+
+
+VARBASE		macro	*starting_address	; was VARINIT
+_varbase	set	\1
+		endm
+
+VARDEF		macro	*name space_needs
+\1		equ	_varbase
+_varbase	set	_varbase+\2
+		endm
+
+
+stz		macro	* address
+		 db	$64,\1
+		endm
+
+stzax		macro	* address
+		 db	$9e,<\1,>\1
+		endm
+
+
+biti		macro	* immediate value
+		db	$89,\1
+		endm
+
+smb0		macro	* address
+		db	$87,\1
+		endm
+smb1		macro	* address
+		db	$97,\1
+		endm
+smb2		macro	* address
+		db	$a7,\1
+		endm
+smb3		macro	* address
+		db	$b7,\1
+		endm
+smb4		macro	* address
+		db	$c7,\1
+		endm
+smb5		macro	* address
+		db	$d7,\1
+		endm
+smb6		macro	* address
+		db	$e7,\1
+		endm
+smb7		macro	* address
+		db	$f7,\1
+		endm
+
+
+
+;-----------------------------------------------------------------------;
+;									;
+; stuff common for all ports, non-critical (run once / loop)		;
+;									;
+DO_SLOW		macro	* port_number					;
+		.local			;				;
+		lda	CIA+C_PA	; check all CD inputs		;
+		cmp	CommonCDo	; changed from previous accptd?	;
+		beq	=over		; nope, do nothing else here	;
+					;				;
+		cmp	CommonCDb	; bouncing?			;
+		beq	=nobounce	; nope ->			;
+					;				;
+		sta	CommonCDb	; save current state		;
+		lda	#64		; reinitialize counter		;
+		sta	CommonCDc	;				;
+		jmp	=over		; skip CD save			;
+					;				;
+=nobounce	dec	CommonCDc	; no, decrement bounce counter	;
+		bpl	=over		; not done yet, so skip CD save	;
+					;				;
+=saveCD		ldx	CDHead		; get write index		;
+		sta	cdbuf,x		; save status in buffer		;
+		inx			;				;
+		cpx	CDTail		; buffer full?			;
+		.if	ne		; no: preserve status:		;
+		 stx	CDHead		; update index in RAM		;
+		 sta	CommonCDo	; save state for the next check	;
+		.end			;				;
+=over		.end	local						;
+		endm							;
+									;
+;-----------------------------------------------------------------------;
+
+
+; port specific stuff (no data transfer)
+
+DO_PORT		macro	* port_number
+		.local			;				;
+		lda	SetUp\1		; reconfiguration request?	;
+		.if	ne		; yes:				;
+		 lda	SoftFlow\1	; get XON/XOFF flag		;
+		 sta	XonOff\1	; save it			;
+		 lda	Param\1		; get parameter			;
+		 ora	#%00010000	; use baud generator for Rx	;
+		 sta	ACIA\1+A_CTRL	; store in control register	;
+		 stz	OutDisable\1	; enable transmit output	;
+		 stz	SetUp\1		; no reconfiguration no more	;
+		.end			;				;
+					;				;
+		lda	InHead\1	; get write index		;
+		sbc	InTail\1	; buffer full soon?		;
+		cmp	#200		; 200 chars or more in buffer?	;
+		lda	Command\1	; get Command reg value		;
+		and	#%11110011	; turn RTS OFF by default	;
+		.if	cc		; still room in buffer:		;
+		 ora	#%00001000	; turn RTS ON			;
+		.end			;				;
+		sta	ACIA\1+A_CMD	; set/clear RTS			;
+					;				;
+		lda	OutFlush\1	; request to flush output buffer;
+		.if	ne		; yessh!			;
+		 lda	OutHead\1	; get head			;
+		 sta	OutTail\1	; save as tail			;
+		 stz	OutDisable\1	; enable transmit output	;
+		 stz	OutFlush\1	; clear request			;
+		.end
+		.end	local
+		endm
+
+
+DO_DATA		macro	* port number
+		.local
+		lda	ACIA\1+A_SR	; read ACIA status register	;
+		biti	[1<<3]		; something received?		;
+		.if	ne		; yes:				;
+		 biti	[1<<1]		; framing error?		;
+		 .if	ne		; yes:				;
+		  lda	ACIA\1+A_DATA	; read received character	;
+		  bne	=SEND		; not break -> ignore it	;
+		  ldx	InHead\1	; get write pointer		;
+		  lda	#CTL_EVENT	; get type of byte		;
+		  sta	ictl\1,x	; save it in InCtl buffer	;
+		  lda	#EVENT_BREAK	; event code			;
+		  sta	ibuf\1,x	; save it as well		;
+		  inx			;				;
+		  cpx	InTail\1	; still room in buffer?		;
+		  .if	ne		; absolutely:			;
+		   stx	InHead\1	; update index in memory	;
+		  .end			;				;
+		  jmp	=SEND		; go check if anything to send	;
+		 .end			;				;
+		 			; normal char received:		;
+		 ldx	InHead\1	; get write index		;
+		 lda	ACIA\1+A_DATA	; read received character	;
+		 sta	ibuf\1,x	; save char in buffer		;
+		 stzax	ictl\1		; set type to CTL_CHAR		;
+		 inx			;				;
+		 cpx	InTail\1	; buffer full?			;
+		 .if	ne		; no: preserve character:	;
+		  stx	InHead\1	; update index in RAM		;
+		 .end			;				;
+		 and	#$7f		; mask off parity if any	;
+		 cmp	#XOFF		; XOFF from remote host?	;
+		 .if	eq		; yes:				;
+		  lda	XonOff\1	; if XON/XOFF handshaking..	;
+		  sta	OutDisable\1	; ..disable transmitter		;
+		 .end			;				;
+		.end			;				;
+					;				;
+					; BUFFER FULL CHECK WAS HERE	;
+					;				;
+=SEND		lda	ACIA\1+A_SR	; transmit register empty?	;
+		and	#[1<<4]		;				;
+		.if	ne		; yes:				;
+		 ldx	OutCtrl\1	; sending out XON/XOFF?		;
+		 .if	ne		; yes:				;
+		  lda	CIA+C_PB	; check CTS signal		;
+		  and	#[1<<\1]	; (for this port only)		;
+		  bne	=DONE		; not allowed to send -> done	;
+		  stx	ACIA\1+A_DATA	; transmit control char		;
+		  stz	OutCtrl\1	; clear flag			;
+		  jmp	=DONE		; and we're done		;
+		 .end			;				;
+					;				;
+		 ldx	OutTail\1	; anything to transmit?		;
+		 cpx	OutHead\1	;				;
+		 .if	ne		; yes:				;
+		  lda	OutDisable\1	; allowed to transmit?		;
+		  .if	eq		; yes:				;
+		   lda	CIA+C_PB	; check CTS signal		;
+		   and	#[1<<\1]	; (for this port only)		;
+		   bne	=DONE		; not allowed to send -> done	;
+		   lda	obuf\1,x	; get a char from buffer	;
+		   sta	ACIA\1+A_DATA	; send it away			;
+		   inc	OutTail\1	; update read index		;
+		  .end			;				;
+		 .end			;				;
+		.end			;				;
+=DONE		.end	local
+		endm
+
+
+
+PORTVAR		macro	* port number
+		VARDEF	InHead\1 1
+		VARDEF	InTail\1 1
+		VARDEF	OutDisable\1 1
+		VARDEF	OutHead\1 1
+		VARDEF	OutTail\1 1
+		VARDEF	OutCtrl\1 1
+		VARDEF	OutFlush\1 1
+		VARDEF	SetUp\1 1
+		VARDEF	Param\1 1
+		VARDEF	Command\1 1
+		VARDEF	SoftFlow\1 1
+		; private:
+		VARDEF	XonOff\1 1
+		endm
+
+
+ VARBASE 0	; start variables at address $0000
+ PORTVAR 0	; define variables for port 0
+ PORTVAR 1	; define variables for port 1
+ PORTVAR 2	; define variables for port 2
+ PORTVAR 3	; define variables for port 3
+ PORTVAR 4	; define variables for port 4
+ PORTVAR 5	; define variables for port 5
+ PORTVAR 6	; define variables for port 6
+
+
+
+ VARDEF	Crystal	1	; 0 = unknown, 1 = normal, 2 = turbo
+ VARDEF	Pad_a	1
+ VARDEF	TimerH	1
+ VARDEF	TimerL	1
+ VARDEF	CDHead	1
+ VARDEF	CDTail	1
+ VARDEF	CDStatus 1
+ VARDEF	Pad_b	1
+
+ VARDEF	CommonCDo 1	; for carrier detect optimization
+ VARDEF	CommonCDc 1	; for carrier detect debouncing
+ VARDEF	CommonCDb 1	; for carrier detect debouncing
+
+
+ VARBASE $0200
+ VARDEF	obuf0 256	; output data (characters only)
+ VARDEF	obuf1 256
+ VARDEF	obuf2 256
+ VARDEF	obuf3 256
+ VARDEF	obuf4 256
+ VARDEF	obuf5 256
+ VARDEF	obuf6 256
+
+ VARDEF	ibuf0 256	; input data (characters, events etc - see ictl)
+ VARDEF	ibuf1 256
+ VARDEF	ibuf2 256
+ VARDEF	ibuf3 256
+ VARDEF	ibuf4 256
+ VARDEF	ibuf5 256
+ VARDEF	ibuf6 256
+
+ VARDEF	ictl0 256	; input control information (type of data in ibuf)
+ VARDEF	ictl1 256
+ VARDEF	ictl2 256
+ VARDEF	ictl3 256
+ VARDEF	ictl4 256
+ VARDEF	ictl5 256
+ VARDEF	ictl6 256
+
+ VARDEF	cdbuf 256	; CD event queue
+
+
+ACIA0		equ	$4400
+ACIA1		equ	$4c00
+ACIA2		equ	$5400
+ACIA3		equ	$5c00
+ACIA4		equ	$6400
+ACIA5		equ	$6c00
+ACIA6		equ	$7400
+
+A_DATA		equ	$00
+A_SR		equ	$02
+A_CMD		equ	$04
+A_CTRL		equ	$06
+;  00	write transmit data	read received data
+;  02	reset ACIA		read status register
+;  04	write command register	read command register
+;  06	write control register	read control register
+
+CIA		equ	$7c00		; 8520 CIA
+C_PA		equ	$00		; port A data register
+C_PB		equ	$02		; port B data register
+C_DDRA		equ	$04		; data direction register for port A
+C_DDRB		equ	$06		; data direction register for port B
+C_TAL		equ	$08		; timer A
+C_TAH		equ	$0a
+C_TBL		equ	$0c		; timer B
+C_TBH		equ	$0e
+C_TODL		equ	$10		; TOD LSB
+C_TODM		equ	$12		; TOD middle byte
+C_TODH		equ	$14		; TOD MSB
+C_DATA		equ	$18		; serial data register
+C_INTCTRL	equ	$1a		; interrupt control register
+C_CTRLA		equ	$1c		; control register A
+C_CTRLB		equ	$1e		; control register B
+
+
+
+
+
+		section	main,code,CODE-2
+
+		db	>CODE,<CODE
+
+;-----------------------------------------------------------------------;
+; here's the initialization code:					;
+;									;
+R_RESET		ldx	#$ff						;
+		txs			; initialize stack pointer	;
+		cld			; in case a 6502 is used...	;
+		ldx	#0		;				;
+		lda	#0		;				;
+		ldy	#Crystal	; this many bytes to clear	;
+clr_loop	sta	0,x		; clear zero page variables	;
+		inx			;				;
+		dey			;				;
+		bne	clr_loop	;				;
+					;				;
+		stz	CommonCDo	; force CD test at boot		;
+		stz	CommonCDb	;				;
+		stz	CDHead		; clear queue			;
+		stz	CDTail		;				;
+					;				;
+		lda	#0		;				;
+		sta	Pad_a		;				;
+		lda	#170		; test cmp			;
+		cmp	#100		;				;
+		.if	cs		;				;
+		 inc	Pad_a		; C was set			;
+		.end			;				;
+									;
+;-----------------------------------------------------------------------;
+; Speed check								;
+;-----------------------------------------------------------------------;
+									;
+		lda	Crystal		; speed already set?		;
+		beq	DoSpeedy	;				;
+		jmp	LOOP		; yes, skip speed test		;
+					;				;
+DoSpeedy	lda	#%10011000	; 8N1, 1200/2400 bps		;
+		sta	ACIA0+A_CTRL	;				;
+		lda	#%00001011	; enable DTR			;
+		sta	ACIA0+A_CMD	;				;
+		lda	ACIA0+A_SR	; read status register		;
+					;				;
+		lda	#%10000000	; disable all ints (unnecessary);
+		sta	CIA+C_INTCTRL	;				;
+		lda	#255		; program the timer		;
+		sta	CIA+C_TAL	;				;
+		sta	CIA+C_TAH	;				;
+					;				;
+		ldx	#0		;				;
+		stx	ACIA0+A_DATA	; transmit a zero		;
+		nop			;				;
+		nop			;				;
+		lda	ACIA0+A_SR	; read status			;
+		nop			;				;
+		nop			;				;
+		stx	ACIA0+A_DATA	; transmit a zero		;
+Speedy1		lda	ACIA0+A_SR	; read status			;
+		and	#[1<<4]		; transmit data reg empty?	;
+		beq	Speedy1		; not yet, wait more		;
+					;				;
+		lda	#%00010001	; load & start the timer	;
+		stx	ACIA0+A_DATA	; transmit one more zero	;
+		sta	CIA+C_CTRLA	;				;
+Speedy2		lda	ACIA0+A_SR	; read status			;
+		and	#[1<<4]		; transmit data reg empty?	;
+		beq	Speedy2		; not yet, wait more		;
+		stx	CIA+C_CTRLA	; stop the timer		;
+					;				;
+		lda	CIA+C_TAL	; copy timer value for 68k	;
+		sta	TimerL		;				;
+		lda	CIA+C_TAH	;				;
+		sta	TimerH		;				;
+		cmp	#$d0		; turbo or normal?		;
+		.if	cs		;				;
+		 lda	#2		; turbo! :-)			;
+		.else			;				;
+		 lda	#1		; normal :-(			;
+		.end			;				;
+		sta	Crystal		;				;
+		lda	#0		;				;
+		sta	ACIA0+A_SR	;				;
+		sta	ACIA0+A_CTRL	; reset UART			;
+		sta	ACIA0+A_CMD	;				;
+									;
+		jmp	LOOP						;
+									;
+;									;
+;-----------------------------------------------------------------------;
+;									;
+; The Real Thing:							;
+;									;
+LOOP		DO_SLOW			; do non-critical things	;
+		jsr	do_input	; check for received data
+		DO_PORT	0
+		jsr	do_input
+		DO_PORT	1
+		jsr	do_input
+		DO_PORT	2
+		jsr	do_input
+		DO_PORT	3
+		jsr	do_input
+		DO_PORT	4
+		jsr	do_input
+		DO_PORT	5
+		jsr	do_input
+		DO_PORT	6
+		jsr	do_input
+		jmp	LOOP
+
+
+do_input	DO_DATA	0
+		DO_DATA	1
+		DO_DATA	2
+		DO_DATA	3
+		DO_DATA	4
+		DO_DATA	5
+		DO_DATA	6
+		rts
+
+
+;-----------------------------------------------------------------------;
+		section	vectors,data,$3ffa
+		dw	$d0d0
+		dw	R_RESET
+		dw	$c0ce
+;-----------------------------------------------------------------------;
+
+
+
+		end
+
+
+
diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232fw.h linux/drivers/char/ser_a2232fw.h
--- v2.4.6/linux/drivers/char/ser_a2232fw.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/ser_a2232fw.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,306 @@
+/* drivers/char/ser_a2232fw.h */
+
+/* $Id: ser_a2232fw.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */
+
+/*
+ * Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                                      
+/* This is the 65EC02 code by Jukka Marin that is executed by
+   the A2232's 65EC02 processor (base address: 0x3800)
+   Source file:	ser_a2232fw.ax
+   Version:	1.3 (951029)
+   Known Bugs:	Cannot send a break yet
+*/
+static unsigned char a2232_65EC02code[] = {
+	0x38, 0x00, 0xA2, 0xFF, 0x9A, 0xD8, 0xA2, 0x00, 
+	0xA9, 0x00, 0xA0, 0x54, 0x95, 0x00, 0xE8, 0x88, 
+	0xD0, 0xFA, 0x64, 0x5C, 0x64, 0x5E, 0x64, 0x58, 
+	0x64, 0x59, 0xA9, 0x00, 0x85, 0x55, 0xA9, 0xAA, 
+	0xC9, 0x64, 0x90, 0x02, 0xE6, 0x55, 0xA5, 0x54, 
+	0xF0, 0x03, 0x4C, 0x92, 0x38, 0xA9, 0x98, 0x8D, 
+	0x06, 0x44, 0xA9, 0x0B, 0x8D, 0x04, 0x44, 0xAD, 
+	0x02, 0x44, 0xA9, 0x80, 0x8D, 0x1A, 0x7C, 0xA9, 
+	0xFF, 0x8D, 0x08, 0x7C, 0x8D, 0x0A, 0x7C, 0xA2, 
+	0x00, 0x8E, 0x00, 0x44, 0xEA, 0xEA, 0xAD, 0x02, 
+	0x44, 0xEA, 0xEA, 0x8E, 0x00, 0x44, 0xAD, 0x02, 
+	0x44, 0x29, 0x10, 0xF0, 0xF9, 0xA9, 0x11, 0x8E, 
+	0x00, 0x44, 0x8D, 0x1C, 0x7C, 0xAD, 0x02, 0x44, 
+	0x29, 0x10, 0xF0, 0xF9, 0x8E, 0x1C, 0x7C, 0xAD, 
+	0x08, 0x7C, 0x85, 0x57, 0xAD, 0x0A, 0x7C, 0x85, 
+	0x56, 0xC9, 0xD0, 0x90, 0x05, 0xA9, 0x02, 0x4C, 
+	0x82, 0x38, 0xA9, 0x01, 0x85, 0x54, 0xA9, 0x00, 
+	0x8D, 0x02, 0x44, 0x8D, 0x06, 0x44, 0x8D, 0x04, 
+	0x44, 0x4C, 0x92, 0x38, 0xAD, 0x00, 0x7C, 0xC5, 
+	0x5C, 0xF0, 0x1F, 0xC5, 0x5E, 0xF0, 0x09, 0x85, 
+	0x5E, 0xA9, 0x40, 0x85, 0x5D, 0x4C, 0xB8, 0x38, 
+	0xC6, 0x5D, 0x10, 0x0E, 0xA6, 0x58, 0x9D, 0x00, 
+	0x17, 0xE8, 0xE4, 0x59, 0xF0, 0x04, 0x86, 0x58, 
+	0x85, 0x5C, 0x20, 0x23, 0x3A, 0xA5, 0x07, 0xF0, 
+	0x0F, 0xA5, 0x0A, 0x85, 0x0B, 0xA5, 0x08, 0x09, 
+	0x10, 0x8D, 0x06, 0x44, 0x64, 0x02, 0x64, 0x07, 
+	0xA5, 0x00, 0xE5, 0x01, 0xC9, 0xC8, 0xA5, 0x09, 
+	0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 
+	0x44, 0xA5, 0x06, 0xF0, 0x08, 0xA5, 0x03, 0x85, 
+	0x04, 0x64, 0x02, 0x64, 0x06, 0x20, 0x23, 0x3A, 
+	0xA5, 0x13, 0xF0, 0x0F, 0xA5, 0x16, 0x85, 0x17, 
+	0xA5, 0x14, 0x09, 0x10, 0x8D, 0x06, 0x4C, 0x64, 
+	0x0E, 0x64, 0x13, 0xA5, 0x0C, 0xE5, 0x0D, 0xC9, 
+	0xC8, 0xA5, 0x15, 0x29, 0xF3, 0xB0, 0x02, 0x09, 
+	0x08, 0x8D, 0x04, 0x4C, 0xA5, 0x12, 0xF0, 0x08, 
+	0xA5, 0x0F, 0x85, 0x10, 0x64, 0x0E, 0x64, 0x12, 
+	0x20, 0x23, 0x3A, 0xA5, 0x1F, 0xF0, 0x0F, 0xA5, 
+	0x22, 0x85, 0x23, 0xA5, 0x20, 0x09, 0x10, 0x8D, 
+	0x06, 0x54, 0x64, 0x1A, 0x64, 0x1F, 0xA5, 0x18, 
+	0xE5, 0x19, 0xC9, 0xC8, 0xA5, 0x21, 0x29, 0xF3, 
+	0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 0x54, 0xA5, 
+	0x1E, 0xF0, 0x08, 0xA5, 0x1B, 0x85, 0x1C, 0x64, 
+	0x1A, 0x64, 0x1E, 0x20, 0x23, 0x3A, 0xA5, 0x2B, 
+	0xF0, 0x0F, 0xA5, 0x2E, 0x85, 0x2F, 0xA5, 0x2C, 
+	0x09, 0x10, 0x8D, 0x06, 0x5C, 0x64, 0x26, 0x64, 
+	0x2B, 0xA5, 0x24, 0xE5, 0x25, 0xC9, 0xC8, 0xA5, 
+	0x2D, 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 
+	0x04, 0x5C, 0xA5, 0x2A, 0xF0, 0x08, 0xA5, 0x27, 
+	0x85, 0x28, 0x64, 0x26, 0x64, 0x2A, 0x20, 0x23, 
+	0x3A, 0xA5, 0x37, 0xF0, 0x0F, 0xA5, 0x3A, 0x85, 
+	0x3B, 0xA5, 0x38, 0x09, 0x10, 0x8D, 0x06, 0x64, 
+	0x64, 0x32, 0x64, 0x37, 0xA5, 0x30, 0xE5, 0x31, 
+	0xC9, 0xC8, 0xA5, 0x39, 0x29, 0xF3, 0xB0, 0x02, 
+	0x09, 0x08, 0x8D, 0x04, 0x64, 0xA5, 0x36, 0xF0, 
+	0x08, 0xA5, 0x33, 0x85, 0x34, 0x64, 0x32, 0x64, 
+	0x36, 0x20, 0x23, 0x3A, 0xA5, 0x43, 0xF0, 0x0F, 
+	0xA5, 0x46, 0x85, 0x47, 0xA5, 0x44, 0x09, 0x10, 
+	0x8D, 0x06, 0x6C, 0x64, 0x3E, 0x64, 0x43, 0xA5, 
+	0x3C, 0xE5, 0x3D, 0xC9, 0xC8, 0xA5, 0x45, 0x29, 
+	0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 0x6C, 
+	0xA5, 0x42, 0xF0, 0x08, 0xA5, 0x3F, 0x85, 0x40, 
+	0x64, 0x3E, 0x64, 0x42, 0x20, 0x23, 0x3A, 0xA5, 
+	0x4F, 0xF0, 0x0F, 0xA5, 0x52, 0x85, 0x53, 0xA5, 
+	0x50, 0x09, 0x10, 0x8D, 0x06, 0x74, 0x64, 0x4A, 
+	0x64, 0x4F, 0xA5, 0x48, 0xE5, 0x49, 0xC9, 0xC8, 
+	0xA5, 0x51, 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 
+	0x8D, 0x04, 0x74, 0xA5, 0x4E, 0xF0, 0x08, 0xA5, 
+	0x4B, 0x85, 0x4C, 0x64, 0x4A, 0x64, 0x4E, 0x20, 
+	0x23, 0x3A, 0x4C, 0x92, 0x38, 0xAD, 0x02, 0x44, 
+	0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 
+	0xAD, 0x00, 0x44, 0xD0, 0x32, 0xA6, 0x00, 0xA9, 
+	0x01, 0x9D, 0x00, 0x10, 0xA9, 0x01, 0x9D, 0x00, 
+	0x09, 0xE8, 0xE4, 0x01, 0xF0, 0x02, 0x86, 0x00, 
+	0x4C, 0x65, 0x3A, 0xA6, 0x00, 0xAD, 0x00, 0x44, 
+	0x9D, 0x00, 0x09, 0x9E, 0x00, 0x10, 0xE8, 0xE4, 
+	0x01, 0xF0, 0x02, 0x86, 0x00, 0x29, 0x7F, 0xC9, 
+	0x13, 0xD0, 0x04, 0xA5, 0x0B, 0x85, 0x02, 0xAD, 
+	0x02, 0x44, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x05, 
+	0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x01, 0xD0, 
+	0x21, 0x8E, 0x00, 0x44, 0x64, 0x05, 0x4C, 0x98, 
+	0x3A, 0xA6, 0x04, 0xE4, 0x03, 0xF0, 0x13, 0xA5, 
+	0x02, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x01, 
+	0xD0, 0x08, 0xBD, 0x00, 0x02, 0x8D, 0x00, 0x44, 
+	0xE6, 0x04, 0xAD, 0x02, 0x4C, 0x89, 0x08, 0xF0, 
+	0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 0x4C, 
+	0xD0, 0x32, 0xA6, 0x0C, 0xA9, 0x01, 0x9D, 0x00, 
+	0x11, 0xA9, 0x01, 0x9D, 0x00, 0x0A, 0xE8, 0xE4, 
+	0x0D, 0xF0, 0x02, 0x86, 0x0C, 0x4C, 0xDA, 0x3A, 
+	0xA6, 0x0C, 0xAD, 0x00, 0x4C, 0x9D, 0x00, 0x0A, 
+	0x9E, 0x00, 0x11, 0xE8, 0xE4, 0x0D, 0xF0, 0x02, 
+	0x86, 0x0C, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 0x04, 
+	0xA5, 0x17, 0x85, 0x0E, 0xAD, 0x02, 0x4C, 0x29, 
+	0x10, 0xF0, 0x2C, 0xA6, 0x11, 0xF0, 0x0F, 0xAD, 
+	0x02, 0x7C, 0x29, 0x02, 0xD0, 0x21, 0x8E, 0x00, 
+	0x4C, 0x64, 0x11, 0x4C, 0x0D, 0x3B, 0xA6, 0x10, 
+	0xE4, 0x0F, 0xF0, 0x13, 0xA5, 0x0E, 0xD0, 0x0F, 
+	0xAD, 0x02, 0x7C, 0x29, 0x02, 0xD0, 0x08, 0xBD, 
+	0x00, 0x03, 0x8D, 0x00, 0x4C, 0xE6, 0x10, 0xAD, 
+	0x02, 0x54, 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 
+	0xF0, 0x1B, 0xAD, 0x00, 0x54, 0xD0, 0x32, 0xA6, 
+	0x18, 0xA9, 0x01, 0x9D, 0x00, 0x12, 0xA9, 0x01, 
+	0x9D, 0x00, 0x0B, 0xE8, 0xE4, 0x19, 0xF0, 0x02, 
+	0x86, 0x18, 0x4C, 0x4F, 0x3B, 0xA6, 0x18, 0xAD, 
+	0x00, 0x54, 0x9D, 0x00, 0x0B, 0x9E, 0x00, 0x12, 
+	0xE8, 0xE4, 0x19, 0xF0, 0x02, 0x86, 0x18, 0x29, 
+	0x7F, 0xC9, 0x13, 0xD0, 0x04, 0xA5, 0x23, 0x85, 
+	0x1A, 0xAD, 0x02, 0x54, 0x29, 0x10, 0xF0, 0x2C, 
+	0xA6, 0x1D, 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 
+	0x04, 0xD0, 0x21, 0x8E, 0x00, 0x54, 0x64, 0x1D, 
+	0x4C, 0x82, 0x3B, 0xA6, 0x1C, 0xE4, 0x1B, 0xF0, 
+	0x13, 0xA5, 0x1A, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 
+	0x29, 0x04, 0xD0, 0x08, 0xBD, 0x00, 0x04, 0x8D, 
+	0x00, 0x54, 0xE6, 0x1C, 0xAD, 0x02, 0x5C, 0x89, 
+	0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 
+	0x00, 0x5C, 0xD0, 0x32, 0xA6, 0x24, 0xA9, 0x01, 
+	0x9D, 0x00, 0x13, 0xA9, 0x01, 0x9D, 0x00, 0x0C, 
+	0xE8, 0xE4, 0x25, 0xF0, 0x02, 0x86, 0x24, 0x4C, 
+	0xC4, 0x3B, 0xA6, 0x24, 0xAD, 0x00, 0x5C, 0x9D, 
+	0x00, 0x0C, 0x9E, 0x00, 0x13, 0xE8, 0xE4, 0x25, 
+	0xF0, 0x02, 0x86, 0x24, 0x29, 0x7F, 0xC9, 0x13, 
+	0xD0, 0x04, 0xA5, 0x2F, 0x85, 0x26, 0xAD, 0x02, 
+	0x5C, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x29, 0xF0, 
+	0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x08, 0xD0, 0x21, 
+	0x8E, 0x00, 0x5C, 0x64, 0x29, 0x4C, 0xF7, 0x3B, 
+	0xA6, 0x28, 0xE4, 0x27, 0xF0, 0x13, 0xA5, 0x26, 
+	0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x08, 0xD0, 
+	0x08, 0xBD, 0x00, 0x05, 0x8D, 0x00, 0x5C, 0xE6, 
+	0x28, 0xAD, 0x02, 0x64, 0x89, 0x08, 0xF0, 0x3B, 
+	0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 0x64, 0xD0, 
+	0x32, 0xA6, 0x30, 0xA9, 0x01, 0x9D, 0x00, 0x14, 
+	0xA9, 0x01, 0x9D, 0x00, 0x0D, 0xE8, 0xE4, 0x31, 
+	0xF0, 0x02, 0x86, 0x30, 0x4C, 0x39, 0x3C, 0xA6, 
+	0x30, 0xAD, 0x00, 0x64, 0x9D, 0x00, 0x0D, 0x9E, 
+	0x00, 0x14, 0xE8, 0xE4, 0x31, 0xF0, 0x02, 0x86, 
+	0x30, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 0x04, 0xA5, 
+	0x3B, 0x85, 0x32, 0xAD, 0x02, 0x64, 0x29, 0x10, 
+	0xF0, 0x2C, 0xA6, 0x35, 0xF0, 0x0F, 0xAD, 0x02, 
+	0x7C, 0x29, 0x10, 0xD0, 0x21, 0x8E, 0x00, 0x64, 
+	0x64, 0x35, 0x4C, 0x6C, 0x3C, 0xA6, 0x34, 0xE4, 
+	0x33, 0xF0, 0x13, 0xA5, 0x32, 0xD0, 0x0F, 0xAD, 
+	0x02, 0x7C, 0x29, 0x10, 0xD0, 0x08, 0xBD, 0x00, 
+	0x06, 0x8D, 0x00, 0x64, 0xE6, 0x34, 0xAD, 0x02, 
+	0x6C, 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 
+	0x1B, 0xAD, 0x00, 0x6C, 0xD0, 0x32, 0xA6, 0x3C, 
+	0xA9, 0x01, 0x9D, 0x00, 0x15, 0xA9, 0x01, 0x9D, 
+	0x00, 0x0E, 0xE8, 0xE4, 0x3D, 0xF0, 0x02, 0x86, 
+	0x3C, 0x4C, 0xAE, 0x3C, 0xA6, 0x3C, 0xAD, 0x00, 
+	0x6C, 0x9D, 0x00, 0x0E, 0x9E, 0x00, 0x15, 0xE8, 
+	0xE4, 0x3D, 0xF0, 0x02, 0x86, 0x3C, 0x29, 0x7F, 
+	0xC9, 0x13, 0xD0, 0x04, 0xA5, 0x47, 0x85, 0x3E, 
+	0xAD, 0x02, 0x6C, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 
+	0x41, 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x20, 
+	0xD0, 0x21, 0x8E, 0x00, 0x6C, 0x64, 0x41, 0x4C, 
+	0xE1, 0x3C, 0xA6, 0x40, 0xE4, 0x3F, 0xF0, 0x13, 
+	0xA5, 0x3E, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 
+	0x20, 0xD0, 0x08, 0xBD, 0x00, 0x07, 0x8D, 0x00, 
+	0x6C, 0xE6, 0x40, 0xAD, 0x02, 0x74, 0x89, 0x08, 
+	0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 
+	0x74, 0xD0, 0x32, 0xA6, 0x48, 0xA9, 0x01, 0x9D, 
+	0x00, 0x16, 0xA9, 0x01, 0x9D, 0x00, 0x0F, 0xE8, 
+	0xE4, 0x49, 0xF0, 0x02, 0x86, 0x48, 0x4C, 0x23, 
+	0x3D, 0xA6, 0x48, 0xAD, 0x00, 0x74, 0x9D, 0x00, 
+	0x0F, 0x9E, 0x00, 0x16, 0xE8, 0xE4, 0x49, 0xF0, 
+	0x02, 0x86, 0x48, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 
+	0x04, 0xA5, 0x53, 0x85, 0x4A, 0xAD, 0x02, 0x74, 
+	0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x4D, 0xF0, 0x0F, 
+	0xAD, 0x02, 0x7C, 0x29, 0x40, 0xD0, 0x21, 0x8E, 
+	0x00, 0x74, 0x64, 0x4D, 0x4C, 0x56, 0x3D, 0xA6, 
+	0x4C, 0xE4, 0x4B, 0xF0, 0x13, 0xA5, 0x4A, 0xD0, 
+	0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x40, 0xD0, 0x08, 
+	0xBD, 0x00, 0x08, 0x8D, 0x00, 0x74, 0xE6, 0x4C, 
+	0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xD0, 0x00, 0x38, 
+	0xCE, 0xC0, 
+};
diff -u --recursive --new-file v2.4.6/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.4.6/linux/drivers/char/serial.c	Sun May 20 12:11:38 2001
+++ linux/drivers/char/serial.c	Sun Jul  8 13:14:37 2001
@@ -59,8 +59,8 @@
  *
  */
 
-static char *serial_version = "5.05a";
-static char *serial_revdate = "2001-03-20";
+static char *serial_version = "5.05c";
+static char *serial_revdate = "2001-07-08";
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -3512,7 +3512,7 @@
 				      struct serial_state *state,
 				      unsigned long flags)
 {
-	unsigned char scratch, scratch2, scratch3;
+	unsigned char scratch, scratch2, scratch3, scratch4;
 
 	/*
 	 * First we check to see if it's an Oxford Semiconductor UART.
@@ -3556,17 +3556,32 @@
 	 * XR16C854.
 	 * 
 	 */
+
+	/* Save the DLL and DLM */
+
 	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	scratch3 = serial_inp(info, UART_DLL);
+	scratch4 = serial_inp(info, UART_DLM);
+
 	serial_outp(info, UART_DLL, 0);
 	serial_outp(info, UART_DLM, 0);
-	state->revision = serial_inp(info, UART_DLL);
+	scratch2 = serial_inp(info, UART_DLL);
 	scratch = serial_inp(info, UART_DLM);
 	serial_outp(info, UART_LCR, 0);
+
 	if (scratch == 0x10 || scratch == 0x14) {
+		if (scratch == 0x10)
+			state->revision = scratch2;
 		state->type = PORT_16850;
 		return;
 	}
 
+	/* Restore the DLL and DLM */
+
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	serial_outp(info, UART_DLL, scratch3);
+	serial_outp(info, UART_DLM, scratch4);
+	serial_outp(info, UART_LCR, 0);
 	/*
 	 * We distinguish between the '654 and the '650 by counting
 	 * how many bytes are in the FIFO.  I'm using this for now,
@@ -3917,14 +3932,14 @@
 
        if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
 	       printk("serial: PNP device '");
-	       printk_pnp_dev_id(board->vendor, board->device);
+	       printk_pnp_dev_id(dev->vendor, dev->device);
 	       printk("' prepare failed\n");
 	       return;
        }
 
        if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
 	       printk("serial: PNP device '");
-	       printk_pnp_dev_id(board->vendor, board->device);
+	       printk_pnp_dev_id(dev->vendor, dev->device);
 	       printk("' activate failed\n");
 	       return;
        }
@@ -3979,10 +3994,7 @@
  * seems to be mainly needed on card using the PLX which also use I/O
  * mapped memory.
  */
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
 	u8 data, *p, irq_config;
@@ -4046,10 +4058,7 @@
 #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
 #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u16 data, *p;
@@ -4078,10 +4087,7 @@
 #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
 #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u8 data;
@@ -4102,17 +4108,14 @@
 }
 
 /* Added for EKF Intel i960 serial boards */
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_inteli960ni_fn(struct pci_dev *dev,
 		   struct pci_board *board,
 		   int enable)
 {
 	unsigned long oldval;
 	
-	if (!(board->subdevice & 0x1000))
+	if (!(pci_get_subdevice(dev) & 0x1000))
 		return(-1);
 
 	if (!enable) /* is there something to deinit? */
@@ -4163,10 +4166,7 @@
 	{ 0, 0 }
 };
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
 	int	i, j;
@@ -4178,7 +4178,7 @@
 	for (i=0; timedia_data[i].num; i++) {
 		ids = timedia_data[i].ids;
 		for (j=0; ids[j]; j++) {
-			if (pci_get_subvendor(dev) == ids[j]) {
+			if (pci_get_subdevice(dev) == ids[j]) {
 				board->num_ports = timedia_data[i].num;
 				return 0;
 			}
@@ -4187,530 +4187,658 @@
 	return 0;
 }
 
+static int __devinit
+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+	return 0;
+}
 
 /*
  * This is the configuration table for all of the PCI serial boards
- * which we support.
- */
+ * which we support.  It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ */
+enum pci_board_num_t {
+	pbn_b0_1_115200,
+	pbn_default = 0,
+
+	pbn_b0_2_115200,
+	pbn_b0_4_115200,
+
+	pbn_b0_1_921600,
+	pbn_b0_2_921600,
+	pbn_b0_4_921600,
+
+	pbn_b0_bt_1_115200,
+	pbn_b0_bt_2_115200,
+	pbn_b0_bt_1_460800,
+	pbn_b0_bt_2_460800,
+
+	pbn_b1_1_115200,
+	pbn_b1_2_115200,
+	pbn_b1_4_115200,
+	pbn_b1_8_115200,
+
+	pbn_b1_2_921600,
+	pbn_b1_4_921600,
+	pbn_b1_8_921600,
+
+	pbn_b1_2_1382400,
+	pbn_b1_4_1382400,
+	pbn_b1_8_1382400,
+
+	pbn_b2_8_115200,
+	pbn_b2_4_460800,
+	pbn_b2_8_460800,
+	pbn_b2_16_460800,
+	pbn_b2_4_921600,
+	pbn_b2_8_921600,
+
+	pbn_b2_bt_1_115200,
+	pbn_b2_bt_2_115200,
+	pbn_b2_bt_4_115200,
+	pbn_b2_bt_2_921600,
+
+	pbn_panacom,
+	pbn_panacom2,
+	pbn_panacom4,
+	pbn_plx_romulus,
+	pbn_oxsemi,
+	pbn_timedia,
+	pbn_intel_i960,
+	pbn_sgi_ioc3,
+#ifdef CONFIG_DDB5074
+	pbn_nec_nile4,
+#endif
+#if 0
+	pbn_dci_pccom8,
+#endif
+	pbn_xircom_combo,
+
+	pbn_siig10x_0,
+	pbn_siig10x_1,
+	pbn_siig10x_2,
+	pbn_siig10x_4,
+	pbn_siig20x_0,
+	pbn_siig20x_2,
+	pbn_siig20x_4,
+	
+	pbn_computone_4,
+	pbn_computone_6,
+	pbn_computone_8,
+};
+
 static struct pci_board pci_boards[] __devinitdata = {
 	/*
-	 * Vendor ID, 	Device ID,
-	 * Subvendor ID,	Subdevice ID,
 	 * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
 	 * Offset to get to next UART's registers,
 	 * Register shift to use for memory-mapped I/O,
 	 * Initialization function, first UART offset
 	 */
+
+	/* Generic serial board, pbn_b0_1_115200, pbn_default */
+	{ SPCI_FL_BASE0, 1, 115200 },		/* pbn_b0_1_115200,
+						   pbn_default */
+
+	{ SPCI_FL_BASE0, 2, 115200 },		/* pbn_b0_2_115200 */
+	{ SPCI_FL_BASE0, 4, 115200 },		/* pbn_b0_4_115200 */
+
+	{ SPCI_FL_BASE0, 1, 921600 },		/* pbn_b0_1_921600 */
+	{ SPCI_FL_BASE0, 2, 921600 },		/* pbn_b0_2_921600 */
+	{ SPCI_FL_BASE0, 4, 921600 },		/* pbn_b0_4_921600 */
+
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+
+	{ SPCI_FL_BASE1, 1, 115200 },		/* pbn_b1_1_115200 */
+	{ SPCI_FL_BASE1, 2, 115200 },		/* pbn_b1_2_115200 */
+	{ SPCI_FL_BASE1, 4, 115200 },		/* pbn_b1_4_115200 */
+	{ SPCI_FL_BASE1, 8, 115200 },		/* pbn_b1_8_115200 */
+
+	{ SPCI_FL_BASE1, 2, 921600 },		/* pbn_b1_2_921600 */
+	{ SPCI_FL_BASE1, 4, 921600 },		/* pbn_b1_4_921600 */
+	{ SPCI_FL_BASE1, 8, 921600 },		/* pbn_b1_8_921600 */
+
+	{ SPCI_FL_BASE1, 2, 1382400 },		/* pbn_b1_2_1382400 */
+	{ SPCI_FL_BASE1, 4, 1382400 },		/* pbn_b1_4_1382400 */
+	{ SPCI_FL_BASE1, 8, 1382400 },		/* pbn_b1_8_1382400 */
+
+	{ SPCI_FL_BASE2, 8, 115200 },		/* pbn_b2_8_115200 */
+	{ SPCI_FL_BASE2, 4, 460800 },		/* pbn_b2_4_460800 */
+	{ SPCI_FL_BASE2, 8, 460800 },		/* pbn_b2_8_460800 */
+	{ SPCI_FL_BASE2, 16, 460800 },		/* pbn_b2_16_460800 */
+	{ SPCI_FL_BASE2, 4, 921600 },		/* pbn_b2_4_921600 */
+	{ SPCI_FL_BASE2, 8, 921600 },		/* pbn_b2_8_921600 */
+
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
+
+	{ SPCI_FL_BASE2, 2, 921600, /* IOMEM */		   /* pbn_panacom */
+		0x400, 7, pci_plx9050_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_panacom2 */
+		0x400, 7, pci_plx9050_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_panacom4 */
+		0x400, 7, pci_plx9050_fn },
+	{ SPCI_FL_BASE2, 4, 921600,			   /* pbn_plx_romulus */
+		0x20, 2, pci_plx9050_fn, 0x03 },
+		/* This board uses the size of PCI Base region 0 to
+		 * signal now many ports are available */
+	{ SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
+	{ SPCI_FL_BASE_TABLE, 1, 921600,		   /* pbn_timedia */
+		0, 0, pci_timedia_fn },
+	/* EKF addition for i960 Boards form EKF with serial port */
+	{ SPCI_FL_BASE0, 32, 921600, /* max 256 ports */   /* pbn_intel_i960 */
+		8<<2, 2, pci_inteli960ni_fn, 0x10000},
+	{ SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,		   /* pbn_sgi_ioc3 */
+		1, 458333, 0, 0, 0, 0x20178 },
+#ifdef CONFIG_DDB5074
+	/*
+	 * NEC Vrc-5074 (Nile 4) builtin UART.
+	 * Conditionally compiled in since this is a motherboard device.
+	 */
+	{ SPCI_FL_BASE0, 1, 520833,			   /* pbn_nec_nile4 */
+		64, 3, NULL, 0x300 },
+#endif
+#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */		   /* pbn_dci_pccom8 */
+	{ SPCI_FL_BASE3, 8, 115200, 8 },
+#endif
+	{ SPCI_FL_BASE0, 1, 115200,			  /* pbn_xircom_combo */
+		0, 0, pci_xircom_fn },
+
+	{ SPCI_FL_BASE2, 1, 460800,			   /* pbn_siig10x_0 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE2, 1, 921600,			   /* pbn_siig10x_1 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siig10x_2 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siig10x_4 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE0, 1, 921600,			   /* pbn_siix20x_0 */
+		0, 0, pci_siig20x_fn },
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siix20x_2 */
+		0, 0, pci_siig20x_fn },
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siix20x_4 */
+		0, 0, pci_siig20x_fn },
+
+	{ SPCI_FL_BASE0, 4, 921600, /* IOMEM */		   /* pbn_computone_4 */
+		0x40, 2, NULL, 0x200 },
+	{ SPCI_FL_BASE0, 6, 921600, /* IOMEM */		   /* pbn_computone_6 */
+		0x40, 2, NULL, 0x200 },
+	{ SPCI_FL_BASE0, 8, 921600, /* IOMEM */		   /* pbn_computone_8 */
+		0x40, 2, NULL, 0x200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int __devinit serial_pci_guess_board(struct pci_dev *dev,
+					   struct pci_board *board)
+{
+	int	num_iomem = 0, num_port = 0, first_port = -1;
+	int	i;
+	
+	/*
+	 * If it is not a communications device or the programming
+	 * interface is greater than 6, give up.
+	 *
+	 * (Should we try to make guesses for multiport serial devices
+	 * later?) 
+	 */
+	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+	    ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+	    (dev->class & 0xff) > 6)
+		return 1;
+
+	for (i=0; i < 6; i++) {
+		if (IS_PCI_REGION_IOPORT(dev, i)) {
+			num_port++;
+			if (first_port == -1)
+				first_port = i;
+		}
+		if (IS_PCI_REGION_IOMEM(dev, i))
+			num_iomem++;
+	}
+
+	/*
+	 * If there is 1 or 0 iomem regions, and exactly one port, use
+	 * it.
+	 */
+	if (num_iomem <= 1 && num_port == 1) {
+		board->flags = first_port;
+		return 0;
+	}
+	return 1;
+}
+
+static int __devinit serial_init_one(struct pci_dev *dev,
+				     const struct pci_device_id *ent)
+{
+	struct pci_board *board, tmp;
+	int rc;
+
+	board = &pci_boards[ent->driver_data];
+
+	rc = pci_enable_device(dev);
+	if (rc) return rc;
+
+	if (ent->driver_data == pbn_default &&
+	    serial_pci_guess_board(dev, board))
+		return -ENODEV;
+	else if (serial_pci_guess_board(dev, &tmp) == 0) {
+		printk(KERN_INFO "Redundant entry in serial pci_table.  "
+		       "Please send the output of\n"
+		       "lspci -vv, this message (%d,%d,%d,%d)\n"
+		       "and the manufacturer and name of "
+		       "serial board or modem board\n"
+		       "to serial-pci-info@lists.sourceforge.net.\n",
+		       dev->vendor, dev->device,
+		       pci_get_subvendor(dev), pci_get_subdevice(dev));
+	}
+		       
+	start_pci_pnp_board(dev, board);
+
+	return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+	int	i;
+
+	/*
+	 * Iterate through all of the ports finding those that belong
+	 * to this PCI device.
+	 */
+	for(i = 0; i < NR_PORTS; i++) {
+		if (rs_table[i].dev != dev)
+			continue;
+		unregister_serial(i);
+		rs_table[i].dev = 0;
+	}
+	/*
+	 * Now execute any board-specific shutdown procedure
+	 */
+	for (i=0; i < NR_PCI_BOARDS; i++) {
+		struct pci_board_inst *brd = &serial_pci_board[i];
+
+		if (serial_pci_board[i].dev != dev)
+			continue;
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
+		serial_pci_board[i].dev = 0;
+	}
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
-		SPCI_FL_BASE1, 8, 1382400 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+		pbn_b1_8_1382400 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
-		SPCI_FL_BASE1, 4, 1382400 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+		pbn_b1_4_1382400 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
-		SPCI_FL_BASE1, 2, 1382400 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+		pbn_b1_2_1382400 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
-		SPCI_FL_BASE1, 8, 1382400 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+		pbn_b1_8_1382400 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
-		SPCI_FL_BASE1, 4, 1382400 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+		pbn_b1_4_1382400 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
-		SPCI_FL_BASE1, 2, 1382400 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+		pbn_b1_2_1382400 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
-		SPCI_FL_BASE1, 8, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+		pbn_b1_8_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
-		SPCI_FL_BASE1, 8, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+		pbn_b1_8_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
-		SPCI_FL_BASE1, 4, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+		pbn_b1_4_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
-		SPCI_FL_BASE1, 4, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+		pbn_b1_4_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
-		SPCI_FL_BASE1, 2, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+		pbn_b1_2_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6,
-		SPCI_FL_BASE1, 8, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+		pbn_b1_8_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1,
-		SPCI_FL_BASE1, 8, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+		pbn_b1_8_921600 },
 	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
 		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1,
-		SPCI_FL_BASE1, 4, 921600 },
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+		pbn_b1_4_921600 },
+
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_1_115200 },
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_2_115200 },
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_4_115200 },
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_2_115200 },
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_4_115200 },
 	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 8, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_8_115200 },
+
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_bt_2_115200 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_bt_2_921600 },
 	/* VScom SPCOM800, from sl@s.pl */
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, 
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 8, 921600 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_8_921600 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 4, 921600 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_4_921600 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_KEYSPAN,
-		PCI_SUBDEVICE_ID_KEYSPAN_SX2,
-		SPCI_FL_BASE2, 2, 921600, /* IOMEM */
-		0x400, 7, pci_plx9050_fn },
+		PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+		pbn_panacom },
 	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0x400, 7, pci_plx9050_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_panacom4 },
 	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0x400, 7, pci_plx9050_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_panacom2 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST4,
-		SPCI_FL_BASE2, 4, 460800 },
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, 
+		pbn_b2_4_460800 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST8,
-		SPCI_FL_BASE2, 8, 460800 },
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, 
+		pbn_b2_8_460800 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST16,
-		SPCI_FL_BASE2, 16, 460800 },
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, 
+		pbn_b2_16_460800 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC,
-		SPCI_FL_BASE2, 16, 460800 },
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, 
+		pbn_b2_16_460800 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-		PCI_SUBDEVICE_ID_CHASE_PCIRAS4,
-		SPCI_FL_BASE2, 4, 460800 },
+		PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, 
+		pbn_b2_4_460800 },
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-		PCI_SUBDEVICE_ID_CHASE_PCIRAS8,
-		SPCI_FL_BASE2, 8, 460800 },
+		PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, 
+		pbn_b2_8_460800 },
 	/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
 	/* (Exoray@isys.ca) */
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
-		0x10b5, 0x106a,
-		SPCI_FL_BASE2, 4, 921600,
-		0x20, 2, pci_plx9050_fn, 0x03 },
+		0x10b5, 0x106a, 0, 0,
+		pbn_plx_romulus },
 	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE1, 4, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_4_115200 },
 	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE1, 2, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_2_115200 },
 	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE1, 8, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_8_115200 },
 	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE1, 8, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_8_115200 },
 	{	PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
-		SPCI_FL_BASE0 , 4, 921600 },
+		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, 
+		pbn_b0_4_921600 },
 	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 , 4, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_4_115200 },
 	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 , 2, 115200 },
-		/* This board uses the size of PCI Base region 0 to
-		 * signal now many ports are available */
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 },
-	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
-		PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID,
-		SPCI_FL_BASE_TABLE, 1, 921600,
-		0, 0, pci_timedia_fn },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_2_115200 },
+
+	/* Digitan DS560-558, from jimd@esoft.com */
+	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_1_115200 },
+
+	/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+	{	PCI_VENDOR_ID_USR, 0x1008,
+		PCI_ANY_ID, PCI_ANY_ID, },
+
+	/* Titan Electronic cards */
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_1_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_2_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_4_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_4_921600 },
+
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 1, 460800,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 1, 460800,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 1, 460800,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 1, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_1 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 1, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_1 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2, 1, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_1 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_4 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_4 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0, 0, pci_siig10x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_4 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_4 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_4 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
-		0, 0, pci_siig20x_fn },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_4 },
+
 	/* Computone devices submitted by Doug McNash dmcnash@computone.com */
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-		SPCI_FL_BASE0, 4, 921600, /* IOMEM */
-		0x40, 2, NULL, 0x200 },
+		0, 0, pbn_computone_4 },
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-		SPCI_FL_BASE0, 8, 921600, /* IOMEM */
-		0x40, 2, NULL, 0x200 },
+		0, 0, pbn_computone_8 },
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-		SPCI_FL_BASE0, 6, 921600, /* IOMEM */
-		0x40, 2, NULL, 0x200 },
-	/* Digitan DS560-558, from jimd@esoft.com */
-	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE1, 1, 115200 },
-	/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
-	{	PCI_VENDOR_ID_USR, 0x1008,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 115200 },
-	/* Titan Electronic cards */
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 2, 921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 4, 921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 4, 921600 },
-	/* EKF addition for i960 Boards form EKF with serial port */
-	{	PCI_VENDOR_ID_INTEL, 0x1960,
-		0xE4BF, PCI_ANY_ID,
-		SPCI_FL_BASE0, 32, 921600, /* max 256 ports */
-		8<<2, 2, pci_inteli960ni_fn, 0x10000},
+		0, 0, pbn_computone_6 },
+
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
+	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+		PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
+
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_1_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_1_460800 },
+
 	/* RAStel 2 port modem, gerg@moreton.com.au */
 	{	PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_bt_2_115200 },
+
+	/* EKF addition for i960 Boards form EKF with serial port */
+	{	PCI_VENDOR_ID_INTEL, 0x1960,
+		0xE4BF, PCI_ANY_ID, 0, 0,
+		pbn_intel_i960 },
+
+	/* Xircom Cardbus/Ethernet combos */
+	{	PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_xircom_combo },
+
 	/*
 	 * Untested PCI modems, sent in from various folks...
 	 */
+
 	/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
 	{	PCI_VENDOR_ID_ROCKWELL, 0x1004,
-		0x1048, 0x1500, 
-		SPCI_FL_BASE1, 1, 115200 },
+		0x1048, 0x1500, 0, 0,
+		pbn_b1_1_115200 },
+
 	{	PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-		0xFF00, 0, SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,
-		1, 458333, 0, 0, 0, 0x20178 },
-#if CONFIG_DDB5074
+		0xFF00, 0, 0, 0,
+		pbn_sgi_ioc3 },
+
+#ifdef CONFIG_DDB5074
 	/*
 	 * NEC Vrc-5074 (Nile 4) builtin UART.
 	 * Conditionally compiled in since this is a motherboard device.
 	 */
 	{	PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE0, 1, 520833,
-		64, 3, NULL, 0x300 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_nec_nile4 },
 #endif
+
 #if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */
 	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
-		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE3, 8, 115200,
-		8 },
-#endif
-	/* Generic serial board */
-	{	0, 0,
-		0, 0,
-		SPCI_FL_BASE0, 1, 115200 },
-};
-
-/*
- * Given a complete unknown PCI device, try to use some heuristics to
- * guess what the configuration might be, based on the pitiful PCI
- * serial specs.  Returns 0 on success, 1 on failure.
- */
-static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
-					   struct pci_board *board)
-{
-	int	num_iomem = 0, num_port = 0, first_port = -1;
-	int	i;
-	
-	/*
-	 * If it is not a communications device or the programming
-	 * interface is greater than 6, give up.
-	 *
-	 * (Should we try to make guesses for multiport serial devices
-	 * later?) 
-	 */
-	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
-	    ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
-	    (dev->class & 0xff) > 6)
-		return 1;
-
-	for (i=0; i < 6; i++) {
-		if (IS_PCI_REGION_IOPORT(dev, i)) {
-			num_port++;
-			if (first_port == -1)
-				first_port = i;
-		}
-		if (IS_PCI_REGION_IOMEM(dev, i))
-			num_iomem++;
-	}
-
-	/*
-	 * If there is 1 or 0 iomem regions, and exactly one port, use
-	 * it.
-	 */
-	if (num_iomem <= 1 && num_port == 1) {
-		board->flags = first_port;
-		return 0;
-	}
-	return 1;
-}
-
-static int __devinit serial_init_one(struct pci_dev *dev,
-				     const struct pci_device_id *ent)
-{
-	struct pci_board *board, tmp;
-	int rc;
-
-	for (board = pci_boards; board->vendor; board++) {
-		if (board->vendor != (unsigned short) PCI_ANY_ID &&
-		    dev->vendor != board->vendor)
-			continue;
-		if (board->device != (unsigned short) PCI_ANY_ID &&
-		    dev->device != board->device)
-			continue;
-		if (board->subvendor != (unsigned short) PCI_ANY_ID &&
-		    pci_get_subvendor(dev) != board->subvendor)
-			continue;
-		if (board->subdevice != (unsigned short) PCI_ANY_ID &&
-		    pci_get_subdevice(dev) != board->subdevice)
-			continue;
-		break;
-	}
-
-	rc = pci_enable_device(dev);
-	if (rc) return rc;
-
-	if (board->vendor == 0 && serial_pci_guess_board(dev, board))
-		return -ENODEV;
-	else if (serial_pci_guess_board(dev, &tmp) == 0) {
-		printk(KERN_INFO "Redundant entry in serial pci_table.  "
-		       "Please send the output of\n"
-		       "lspci -vv, this message (%d,%d,%d,%d)\n"
-		       "and the manufacturer and name of "
-		       "serial board or modem board\n"
-		       "to serial-pci-info@lists.sourceforge.net.\n",
-		       dev->vendor, dev->device,
-		       pci_get_subvendor(dev), pci_get_subdevice(dev));
-	}
-		       
-	start_pci_pnp_board(dev, board);
-
-	return 0;
-}
-
-static void __devexit serial_remove_one(struct pci_dev *dev)
-{
-	int	i;
-
-	/*
-	 * Iterate through all of the ports finding those that belong
-	 * to this PCI device.
-	 */
-	for(i = 0; i < NR_PORTS; i++) {
-		if (rs_table[i].dev != dev)
-			continue;
-		unregister_serial(i);
-		rs_table[i].dev = 0;
-	}
-	/*
-	 * Now execute any board-specific shutdown procedure
-	 */
-	for (i=0; i < NR_PCI_BOARDS; i++) {
-		struct pci_board_inst *brd = &serial_pci_board[i];
-
-		if (serial_pci_board[i].dev != dev)
-			continue;
-		if (brd->board.init_fn)
-			(brd->board.init_fn)(brd->dev, &brd->board, 0);
-		if (DEACTIVATE_FUNC(brd->dev))
-			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
-		serial_pci_board[i].dev = 0;
-	}
-}
-
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_dci_pccom8 },
+#endif
 
-static struct pci_device_id serial_pci_tbl[] __devinitdata = {
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 	 PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -4746,7 +4874,7 @@
 	 * not to attempt to unregister the driver later
 	 */
 	if (pci_module_init (&serial_pci_driver) != 0)
-		serial_pci_driver.name[0] = 0;
+		serial_pci_driver.name = "";
 
 #ifdef SERIAL_DEBUG_PCI
 	printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
@@ -5153,11 +5281,9 @@
 			       break;
 
 	       if (pnp_board->vendor) {
-		       board.vendor = pnp_board->vendor;
-		       board.device = pnp_board->device;
 		       /* Special case that's more efficient to hardcode */
-		       if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
-			    board.device == ISAPNP_DEVICE(0x1021)))
+		       if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+			    pnp_board->device == ISAPNP_DEVICE(0x1021)))
 			       board.flags |= SPCI_FL_NO_SHIRQ;
 	       } else {
 		       if (serial_pnp_guess_board(dev, &board))
diff -u --recursive --new-file v2.4.6/linux/drivers/char/sonypi.c linux/drivers/char/sonypi.c
--- v2.4.6/linux/drivers/char/sonypi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sonypi.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,716 @@
+/* 
+ * Sony Programmable I/O Control Device driver for VAIO
+ *
+ * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * 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/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "sonypi.h"
+#include <linux/sonypi.h>
+
+static struct sonypi_device sonypi_device;
+static int minor = -1;
+static int verbose; /* = 0 */
+static int fnkeyinit; /* = 0 */
+static int camera; /* = 0 */
+
+/* Inits the queue */
+static inline void sonypi_initq(void) {
+        sonypi_device.queue.head = sonypi_device.queue.tail = 0;
+	sonypi_device.queue.len = 0;
+	sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+	init_waitqueue_head(&sonypi_device.queue.proc_list);
+}
+
+/* Pulls an event from the queue */
+static inline unsigned char sonypi_pullq(void) {
+        unsigned char result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
+	if (!sonypi_device.queue.len) {
+		spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
+		return 0;
+	}
+	result = sonypi_device.queue.buf[sonypi_device.queue.head];
+        sonypi_device.queue.head++;
+	sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
+	sonypi_device.queue.len--;
+	spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
+        return result;
+}
+
+/* Pushes an event into the queue */
+static inline void sonypi_pushq(unsigned char event) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
+	if (sonypi_device.queue.len == SONYPI_BUF_SIZE) {
+		/* remove the first element */
+        	sonypi_device.queue.head++;
+		sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
+		sonypi_device.queue.len--;
+	}
+	sonypi_device.queue.buf[sonypi_device.queue.tail] = event;
+	sonypi_device.queue.tail++;
+	sonypi_device.queue.tail &= (SONYPI_BUF_SIZE - 1);
+	sonypi_device.queue.len++;
+
+	kill_fasync(&sonypi_device.queue.fasync, SIGIO, POLL_IN);
+	wake_up_interruptible(&sonypi_device.queue.proc_list);
+	spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
+}
+
+/* Tests if the queue is empty */
+static inline int sonypi_emptyq(void) {
+        int result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
+        result = (sonypi_device.queue.len == 0);
+	spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
+        return result;
+}
+
+static void sonypi_ecrset(u16 addr, u16 value) {
+	int n = 100;
+
+	while (n-- && (inw_p(SONYPI_CST_IOPORT) & 3))
+		udelay(1);
+	outw_p(0x81, SONYPI_CST_IOPORT);
+	while (inw_p(SONYPI_CST_IOPORT) & 2)
+		udelay(1);
+	outw_p(addr, SONYPI_DATA_IOPORT);
+	while (inw_p(SONYPI_CST_IOPORT) & 2)
+		udelay(1);
+	outw_p(value, SONYPI_DATA_IOPORT);
+	while (inw_p(SONYPI_CST_IOPORT) & 2)
+		udelay(1);
+}
+
+static u16 sonypi_ecrget(u16 addr) {
+	int n = 100;
+
+	while (n-- && (inw_p(SONYPI_CST_IOPORT) & 3))
+		udelay(1);
+	outw_p(0x80, SONYPI_CST_IOPORT);
+	while (inw_p(SONYPI_CST_IOPORT) & 2)
+		udelay(1);
+	outw_p(addr, SONYPI_DATA_IOPORT);
+	while (inw_p(SONYPI_CST_IOPORT) & 2)
+		udelay(1);
+	return inw_p(SONYPI_DATA_IOPORT);
+}
+
+/* Initializes the device - this comes from the AML code in the ACPI bios */
+static void __devinit sonypi_normal_srs(void) {
+	u32 v;
+
+	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
+	v = (v & 0xFFFF0000) | ((u32)sonypi_device.ioport1);
+	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
+
+	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
+	v = (v & 0xFFF0FFFF) | 
+	    (((u32)sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
+	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
+
+	v = inl(SONYPI_IRQ_PORT);
+	v &= ~(((u32)0x3) << SONYPI_IRQ_SHIFT);
+	v |= (((u32)sonypi_device.bits) << SONYPI_IRQ_SHIFT);
+	outl(v, SONYPI_IRQ_PORT);
+
+	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
+	v = (v & 0xFF1FFFFF) | 0x00C00000;
+	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
+}
+
+static void __devinit sonypi_r505_srs(void) {
+	sonypi_ecrset(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8);
+	sonypi_ecrset(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF);
+	sonypi_ecrset(SONYPI_SIRQ,  sonypi_device.bits);
+	udelay(10);
+}
+
+/* Disables the device - this comes from the AML code in the ACPI bios */
+static void __devexit sonypi_normal_dis(void) {
+	u32 v;
+
+	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
+	v = v & 0xFF3FFFFF;
+	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
+
+	v = inl(SONYPI_IRQ_PORT);
+	v |= (0x3 << SONYPI_IRQ_SHIFT);
+	outl(v, SONYPI_IRQ_PORT);
+}
+
+static void __devexit sonypi_r505_dis(void) {
+	sonypi_ecrset(SONYPI_SHIB, 0);
+	sonypi_ecrset(SONYPI_SLOB, 0);
+	sonypi_ecrset(SONYPI_SIRQ, 0);
+}
+
+static u8 sonypi_call1(u8 dev) {
+	u8 v1, v2;
+
+	while (inb_p(sonypi_device.ioport2) & 2)
+		udelay(1);
+	outb(dev, sonypi_device.ioport2);
+	v1 = inb_p(sonypi_device.ioport2);
+	v2 = inb_p(sonypi_device.ioport1);
+	return v2;
+}
+
+static u8 sonypi_call2(u8 dev, u8 fn) {
+	u8 v1;
+
+	while (inb_p(sonypi_device.ioport2) & 2)
+		udelay(1);
+	outb(dev, sonypi_device.ioport2);
+
+	while (inb_p(sonypi_device.ioport2) & 2)
+		udelay(1);
+	outb(fn, sonypi_device.ioport1);
+
+	v1 = inb_p(sonypi_device.ioport1);
+	return v1;
+}
+
+static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
+	u8 v1;
+
+	while (inb_p(sonypi_device.ioport2) & 2)
+		udelay(1);
+	outb(dev, sonypi_device.ioport2);
+
+	while (inb_p(sonypi_device.ioport2) & 2)
+		udelay(1);
+	outb(fn, sonypi_device.ioport1);
+
+	while (inb_p(sonypi_device.ioport2) & 2)
+		udelay(1);
+	outb(v, sonypi_device.ioport1);
+
+	v1 = inb_p(sonypi_device.ioport1);
+	return v1;
+}
+
+static u8 sonypi_read(u8 fn) {
+	u8 v1, v2;
+	int n = 100;
+
+	while (n--) {
+		v1 = sonypi_call2(0x8f, fn);
+		v2 = sonypi_call2(0x8f, fn);
+		if (v1 == v2 && v1 != 0xff)
+			return v1;
+	}
+	return 0xff;
+}
+
+/* Set brightness, hue etc */
+static void sonypi_set(u8 fn, u8 v) {
+	int n = 100;
+	
+	while (n--)
+		if (sonypi_call3(0x90, fn, v) == 0) 
+			break;
+}
+
+/* Tests if the camera is ready */
+static int sonypi_camera_ready(void) {
+	u8 v;
+
+	v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
+	return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
+}
+
+/* Turns the camera off */
+static void sonypi_camera_off(void) {
+
+	sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
+
+	if (!sonypi_device.camera_power)
+		return;
+
+	sonypi_call2(0x91, 0); 
+	sonypi_device.camera_power = 0;
+}
+
+/* Turns the camera on */
+static void sonypi_camera_on(void) {
+	int i, j;
+
+	if (sonypi_device.camera_power)
+		return;
+
+	for (j = 5; j > 0; j--) {
+
+		while (sonypi_call2(0x91, 0x1) != 0) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+		sonypi_call1(0x93);
+
+		for (i = 400; i > 0; i--) {
+			if (sonypi_camera_ready())
+				break;
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+		if (i != 0)
+			break;
+	}
+	
+	if (j == 0) {
+		printk(KERN_WARNING "sonypi: failed to power on camera\n");
+		return;
+	}
+
+	sonypi_set(0x10, 0x5a);
+	sonypi_device.camera_power = 1;
+}
+
+/* Interrupt handler: some event is available */
+void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
+	u8 v1, v2, event = 0;
+	int i;
+	u8 sonypi_jogger_ev, sonypi_fnkey_ev;
+
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) {
+		sonypi_jogger_ev = SONYPI_R505_JOGGER_EV;
+		sonypi_fnkey_ev = SONYPI_R505_FNKEY_EV;
+	}
+	else {
+		sonypi_jogger_ev = SONYPI_NORMAL_JOGGER_EV;
+		sonypi_fnkey_ev = SONYPI_NORMAL_FNKEY_EV;
+	}
+
+	v1 = inb_p(sonypi_device.ioport1);
+	v2 = inb_p(sonypi_device.ioport2);
+
+	if ((v2 & sonypi_jogger_ev) == sonypi_jogger_ev) {
+		for (i = 0; sonypi_joggerev[i].event; i++)
+			if (sonypi_joggerev[i].data == v1) {
+				event = sonypi_joggerev[i].event;
+				goto found;
+			}
+	}
+	if ((v2 & SONYPI_CAPTURE_EV) == SONYPI_CAPTURE_EV) {
+		for (i = 0; sonypi_captureev[i].event; i++)
+			if (sonypi_captureev[i].data == v1) {
+				event = sonypi_captureev[i].event;
+				goto found;
+			}
+	}
+	if ((v2 & sonypi_fnkey_ev) == sonypi_fnkey_ev) {
+		for (i = 0; sonypi_fnkeyev[i].event; i++)
+			if (sonypi_fnkeyev[i].data == v1) {
+				event = sonypi_fnkeyev[i].event;
+				goto found;
+			}
+	}
+	if ((v2 & SONYPI_BLUETOOTH_EV) == SONYPI_BLUETOOTH_EV) {
+		for (i = 0; sonypi_blueev[i].event; i++)
+			if (sonypi_blueev[i].data == v1) {
+				event = sonypi_blueev[i].event;
+				goto found;
+			}
+	}
+	if (verbose)
+		printk(KERN_WARNING 
+		       "sonypi: unknown event port1=0x%x,port2=0x%x\n",v1,v2);
+	return;
+
+found:
+	sonypi_pushq(event);
+}
+
+/* External camera command (exported to the motion eye v4l driver) */
+u8 sonypi_camera_command(int command, u8 value) {
+	u8 ret = 0;
+
+	if (!camera)
+		return 0;
+
+	down(&sonypi_device.lock);
+
+	switch(command) {
+		case SONYPI_COMMAND_GETCAMERA:
+			ret = sonypi_camera_ready();
+			break;
+		case SONYPI_COMMAND_SETCAMERA:
+			if (value)
+				sonypi_camera_on();
+			else
+				sonypi_camera_off();
+			break;
+		case SONYPI_COMMAND_GETCAMERABRIGHTNESS:
+			ret = sonypi_read(SONYPI_CAMERA_BRIGHTNESS);
+			break;
+		case SONYPI_COMMAND_SETCAMERABRIGHTNESS:
+			sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERACONTRAST:
+			ret = sonypi_read(SONYPI_CAMERA_CONTRAST);
+			break;
+		case SONYPI_COMMAND_SETCAMERACONTRAST:
+			sonypi_set(SONYPI_CAMERA_CONTRAST, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERAHUE:
+			ret = sonypi_read(SONYPI_CAMERA_HUE);
+			break;
+		case SONYPI_COMMAND_SETCAMERAHUE:
+			sonypi_set(SONYPI_CAMERA_HUE, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERACOLOR:
+			ret = sonypi_read(SONYPI_CAMERA_COLOR);
+			break;
+		case SONYPI_COMMAND_SETCAMERACOLOR:
+			sonypi_set(SONYPI_CAMERA_COLOR, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERASHARPNESS:
+			ret = sonypi_read(SONYPI_CAMERA_SHARPNESS);
+			break;
+		case SONYPI_COMMAND_SETCAMERASHARPNESS:
+			sonypi_set(SONYPI_CAMERA_SHARPNESS, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERAPICTURE:
+			ret = sonypi_read(SONYPI_CAMERA_PICTURE);
+			break;
+		case SONYPI_COMMAND_SETCAMERAPICTURE:
+			sonypi_set(SONYPI_CAMERA_PICTURE, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERAAGC:
+			ret = sonypi_read(SONYPI_CAMERA_AGC);
+			break;
+		case SONYPI_COMMAND_SETCAMERAAGC:
+			sonypi_set(SONYPI_CAMERA_AGC, value);
+			break;
+		case SONYPI_COMMAND_GETCAMERADIRECTION:
+			ret = sonypi_read(SONYPI_CAMERA_STATUS);
+			ret &= SONYPI_DIRECTION_BACKWARDS;
+			break;
+		case SONYPI_COMMAND_GETCAMERAROMVERSION:
+			ret = sonypi_read(SONYPI_CAMERA_ROMVERSION);
+			break;
+		case SONYPI_COMMAND_GETCAMERAREVISION:
+			ret = sonypi_read(SONYPI_CAMERA_REVISION);
+			break;
+	}
+	up(&sonypi_device.lock);
+	return ret;
+}
+
+static int sonypi_misc_fasync(int fd, struct file *filp, int on) {
+	int retval;
+
+	retval = fasync_helper(fd, filp, on, &sonypi_device.queue.fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static int sonypi_misc_release(struct inode * inode, struct file * file) {
+	sonypi_misc_fasync(-1, file, 0);
+	down(&sonypi_device.lock);
+	sonypi_device.open_count--;
+	up(&sonypi_device.lock);
+	return 0;
+}
+
+static int sonypi_misc_open(struct inode * inode, struct file * file) {
+	down(&sonypi_device.lock);
+	if (sonypi_device.open_count)
+		goto out;
+	sonypi_device.open_count++;
+	/* Flush input queue */
+	sonypi_initq();
+out:
+	up(&sonypi_device.lock);
+	return 0;
+}
+
+static ssize_t sonypi_misc_read(struct file * file, char * buf, 
+		                size_t count, loff_t *pos) {
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t i = count;
+	unsigned char c;
+
+	if (sonypi_emptyq()) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		add_wait_queue(&sonypi_device.queue.proc_list, &wait);
+repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (sonypi_emptyq() && !signal_pending(current)) {
+			schedule();
+			goto repeat;
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&sonypi_device.queue.proc_list, &wait);
+	}
+	while (i > 0 && !sonypi_emptyq()) {
+		c = sonypi_pullq();
+		put_user(c, buf++);
+		i--;
+        }
+	if (count - i) {
+		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+		return count-i;
+	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+	return 0;
+}
+
+static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) {
+	poll_wait(file, &sonypi_device.queue.proc_list, wait);
+	if (!sonypi_emptyq())
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, 
+			     unsigned int cmd, unsigned long arg) {
+	int ret = 0;
+	u8 val;
+
+	down(&sonypi_device.lock);
+	switch (cmd) {
+		case SONYPI_IOCGBRT:
+			val = sonypi_ecrget(0x96) & 0xff;
+			if (copy_to_user((u8 *)arg, &val, sizeof(val))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			break;
+		case SONYPI_IOCSBRT:
+			if (copy_from_user(&val, (u8 *)arg, sizeof(val))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			sonypi_ecrset(0x96, val);
+			break;
+	default:
+		ret = -EINVAL;
+	}
+out:
+	up(&sonypi_device.lock);
+	return ret;
+}
+
+static struct file_operations sonypi_misc_fops = {
+	owner:		THIS_MODULE,
+	read:		sonypi_misc_read,
+	poll:		sonypi_misc_poll,
+	open:		sonypi_misc_open,
+	release:	sonypi_misc_release,
+	fasync: 	sonypi_misc_fasync,
+	ioctl:		sonypi_misc_ioctl,
+};
+
+struct miscdevice sonypi_misc_device = {
+	-1, "sonypi", &sonypi_misc_fops
+};
+
+static int __devinit sonypi_probe(struct pci_dev *pcidev, 
+		                  const struct pci_device_id *ent) {
+	int i, ret;
+	struct sonypi_ioport_list *ioport_list;
+	struct sonypi_irq_list *irq_list;
+
+	if (sonypi_device.dev) {
+		printk(KERN_ERR "sonypi: only one device allowed!\n"),
+		ret = -EBUSY;
+		goto out1;
+	}
+	sonypi_device.dev = pcidev;
+	sonypi_device.model = (int)ent->driver_data;
+	sonypi_initq();
+	init_MUTEX(&sonypi_device.lock);
+	
+	if (pci_enable_device(pcidev)) {
+		printk(KERN_ERR "sonypi: pci_enable_device failed\n");
+		ret = -EIO;
+		goto out1;
+	}
+
+	sonypi_misc_device.minor = (minor == -1) ? 
+		MISC_DYNAMIC_MINOR : minor;
+	if ((ret = misc_register(&sonypi_misc_device))) {
+		printk(KERN_ERR "sonypi: misc_register failed\n");
+		goto out1;
+	}
+
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) {
+		ioport_list = sonypi_r505_ioport_list;
+		sonypi_device.region_size = SONYPI_R505_REGION_SIZE;
+		irq_list = sonypi_r505_irq_list;
+	}
+	else {
+		ioport_list = sonypi_normal_ioport_list;
+		sonypi_device.region_size = SONYPI_NORMAL_REGION_SIZE;
+		irq_list = sonypi_normal_irq_list;
+	}
+
+	for (i = 0; ioport_list[i].port1; i++) {
+		if (request_region(ioport_list[i].port1, 
+				   sonypi_device.region_size, 
+				   "Sony Programable I/O Device")) {
+			/* get the ioport */
+			sonypi_device.ioport1 = ioport_list[i].port1;
+			sonypi_device.ioport2 = ioport_list[i].port2;
+			break;
+		}
+	}
+	if (!sonypi_device.ioport1) {
+		printk(KERN_ERR "sonypi: request_region failed\n");
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	for (i = 0; irq_list[i].irq; i++) {
+		if (!request_irq(irq_list[i].irq, sonypi_irq, 
+				 SA_INTERRUPT, "sonypi", sonypi_irq)) {
+			sonypi_device.irq = irq_list[i].irq;
+			sonypi_device.bits = irq_list[i].bits;
+			break;
+		}
+	}
+	if (!sonypi_device.irq ) {
+		printk(KERN_ERR "sonypi: request_irq failed\n");
+		ret = -ENODEV;
+		goto out3;
+	}
+
+	if (fnkeyinit)
+		outb(0xf0, 0xb2);
+
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505)
+		sonypi_r505_srs();
+	else
+		sonypi_normal_srs();
+
+	sonypi_call1(0x82);
+	sonypi_call2(0x81, 0xff);
+	sonypi_call1(0x92); 
+
+	printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver v%d.%d.\n",
+	       SONYPI_DRIVER_MAJORVERSION,
+	       SONYPI_DRIVER_MINORVERSION);
+	printk(KERN_INFO "sonypi: detected %s model, camera = %s\n",
+	       (sonypi_device.model == SONYPI_DEVICE_MODEL_NORMAL) ?
+	       "normal" : "R505",
+	       camera ? "on" : "off");
+	printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
+	       sonypi_device.irq, 
+	       sonypi_device.ioport1, sonypi_device.ioport2);
+	if (minor == -1)
+		printk(KERN_INFO "sonypi: device allocated minor is %d\n",
+		       sonypi_misc_device.minor);
+
+	return 0;
+
+out3:
+	release_region(sonypi_device.ioport1, sonypi_device.region_size);
+out2:
+	misc_deregister(&sonypi_misc_device);
+out1:
+	return ret;
+}
+
+static void __devexit sonypi_remove(struct pci_dev *pcidev) {
+	sonypi_call2(0x81, 0); /* make sure we don't get any more events */
+	if (camera)
+		sonypi_camera_off();
+	if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505)
+		sonypi_r505_dis();
+	else
+		sonypi_normal_dis();
+	free_irq(sonypi_device.irq, sonypi_irq);
+	release_region(sonypi_device.ioport1, sonypi_device.region_size);
+	misc_deregister(&sonypi_misc_device);
+	printk(KERN_INFO "sonypi: removed.\n");
+}
+
+static struct pci_device_id sonypi_id_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, 
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+	  (unsigned long) SONYPI_DEVICE_MODEL_NORMAL },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+	  (unsigned long) SONYPI_DEVICE_MODEL_R505 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, sonypi_id_tbl);
+
+static struct pci_driver sonypi_driver = {
+	name:		"sonypi",
+	id_table:	sonypi_id_tbl,
+	probe:		sonypi_probe,
+	remove:		sonypi_remove,
+};
+
+static int __init sonypi_init_module(void) {
+	return pci_module_init(&sonypi_driver);
+}
+
+static void __exit sonypi_cleanup_module(void) {
+	pci_unregister_driver(&sonypi_driver);
+}
+
+/* Module entry points */
+module_init(sonypi_init_module);
+module_exit(sonypi_cleanup_module);
+
+MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
+
+MODULE_PARM(minor,"i");
+MODULE_PARM_DESC(minor, "minor number of the misc device, default is -1 (automatic)");
+MODULE_PARM(verbose,"i");
+MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
+MODULE_PARM(fnkeyinit,"i");
+MODULE_PARM_DESC(fnkeyinit, "set this if your Fn keys do not generate any event");
+MODULE_PARM(camera,"i");
+MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
+
+EXPORT_SYMBOL(sonypi_camera_command);
diff -u --recursive --new-file v2.4.6/linux/drivers/char/sonypi.h linux/drivers/char/sonypi.h
--- v2.4.6/linux/drivers/char/sonypi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sonypi.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,228 @@
+/* 
+ * Sony Programmable I/O Control Device driver for VAIO
+ *
+ * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * 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 _SONYPI_PRIV_H_ 
+#define _SONYPI_PRIV_H_
+
+#ifdef __KERNEL__
+
+#define SONYPI_DRIVER_MAJORVERSION	1
+#define SONYPI_DRIVER_MINORVERSION	2
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include "linux/sonypi.h"
+
+/* Normal models use those */
+#define SONYPI_IRQ_PORT			0x8034
+#define SONYPI_IRQ_SHIFT		22
+#define SONYPI_BASE			0x50
+#define SONYPI_G10A			(SONYPI_BASE+0x14)
+#define SONYPI_NORMAL_REGION_SIZE	0x08
+
+/* R505 series specifics */
+#define SONYPI_SIRQ		0x9b
+#define SONYPI_SLOB		0x9c
+#define SONYPI_SHIB		0x9d
+#define SONYPI_R505_REGION_SIZE	0x20
+
+/* ioports used for brightness and R505 events */
+#define SONYPI_DATA_IOPORT	0x62
+#define SONYPI_CST_IOPORT	0x66
+
+/* The set of possible ioports */
+struct sonypi_ioport_list {
+	u16	port1;
+	u16	port2;
+};
+
+static struct sonypi_ioport_list sonypi_normal_ioport_list[] = {
+	{ 0x10c0, 0x10c4 },	/* looks like the default on C1Vx */
+	{ 0x1080, 0x1084 },
+	{ 0x1090, 0x1094 },
+	{ 0x10a0, 0x10a4 },
+	{ 0x10b0, 0x10b4 },
+	{ 0x0, 0x0 }
+};
+
+static struct sonypi_ioport_list sonypi_r505_ioport_list[] = {
+	{ 0x1080, 0x1084 },
+	{ 0x10a0, 0x10a4 },
+	{ 0x10c0, 0x10c4 },
+	{ 0x10e0, 0x10e4 },
+	{ 0x0, 0x0 }
+};
+
+/* The set of possible interrupts */
+struct sonypi_irq_list {
+	u16	irq;
+	u16	bits;
+};
+
+static struct sonypi_irq_list sonypi_normal_irq_list[] = {
+	{ 11, 0x2 },	/* IRQ 11, GO22=0,GO23=1 in AML */
+	{ 10, 0x1 },	/* IRQ 10, GO22=1,GO23=0 in AML */
+	{  5, 0x0 },	/* IRQ  5, GO22=0,GO23=0 in AML */
+	{  0, 0x3 }	/* no IRQ, GO22=1,GO23=1 in AML */
+};
+
+static struct sonypi_irq_list sonypi_r505_irq_list[] = {
+	{ 11, 0x80 },	/* IRQ 11, 0x80 in SIRQ in AML */
+	{ 10, 0x40 },	/* IRQ 10, 0x40 in SIRQ in AML */
+	{  9, 0x20 },	/* IRQ  9, 0x20 in SIRQ in AML */
+	{  6, 0x10 },	/* IRQ  6, 0x10 in SIRQ in AML */
+	{  0, 0x00 }	/* no IRQ, 0x00 in SIRQ in AML */
+};
+
+#define SONYPI_CAMERA_BRIGHTNESS		0
+#define SONYPI_CAMERA_CONTRAST			1
+#define SONYPI_CAMERA_HUE			2
+#define SONYPI_CAMERA_COLOR			3
+#define SONYPI_CAMERA_SHARPNESS			4
+
+#define SONYPI_CAMERA_PICTURE			5
+#define SONYPI_CAMERA_EXPOSURE_MASK		0xC
+#define SONYPI_CAMERA_WHITE_BALANCE_MASK	0x3
+#define SONYPI_CAMERA_PICTURE_MODE_MASK		0x30
+#define SONYPI_CAMERA_MUTE_MASK			0x40
+
+/* the rest don't need a loop until not 0xff */
+#define SONYPI_CAMERA_AGC			6
+#define SONYPI_CAMERA_AGC_MASK			0x30
+#define SONYPI_CAMERA_SHUTTER_MASK 		0x7
+
+#define SONYPI_CAMERA_SHUTDOWN_REQUEST		7
+#define SONYPI_CAMERA_CONTROL			0x10
+
+#define SONYPI_CAMERA_STATUS 			7
+#define SONYPI_CAMERA_STATUS_READY 		0x2
+#define SONYPI_CAMERA_STATUS_POSITION		0x4
+
+#define SONYPI_DIRECTION_BACKWARDS 		0x4
+
+#define SONYPI_CAMERA_REVISION 			8
+#define SONYPI_CAMERA_ROMVERSION 		9
+
+/* key press event data (ioport2) */
+#define SONYPI_NORMAL_JOGGER_EV	0x10
+#define SONYPI_R505_JOGGER_EV	0x08
+#define SONYPI_CAPTURE_EV	0x60
+#define SONYPI_NORMAL_FNKEY_EV	0x20
+#define SONYPI_R505_FNKEY_EV	0x08
+#define SONYPI_BLUETOOTH_EV	0x30
+
+struct sonypi_event {
+	u8	data;
+	u8	event;
+};
+
+/* The set of possible jogger events  */
+static struct sonypi_event sonypi_joggerev[] = {
+	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
+	{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
+	{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
+	{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
+	{ 0x00, SONYPI_EVENT_JOGDIAL_RELEASED },
+	{ 0x00, 0x00 }
+};
+
+/* The set of possible capture button events */
+static struct sonypi_event sonypi_captureev[] = {
+	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
+	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
+	{ 0x00, SONYPI_EVENT_CAPTURE_RELEASED },
+	{ 0x00, 0x00 }
+};
+
+/* The set of possible fnkeys events */
+static struct sonypi_event sonypi_fnkeyev[] = {
+	{ 0x10, SONYPI_EVENT_FNKEY_ESC },
+	{ 0x11, SONYPI_EVENT_FNKEY_F1 },
+	{ 0x12, SONYPI_EVENT_FNKEY_F2 },
+	{ 0x13, SONYPI_EVENT_FNKEY_F3 },
+	{ 0x14, SONYPI_EVENT_FNKEY_F4 },
+	{ 0x15, SONYPI_EVENT_FNKEY_F5 },
+	{ 0x16, SONYPI_EVENT_FNKEY_F6 },
+	{ 0x17, SONYPI_EVENT_FNKEY_F7 },
+	{ 0x18, SONYPI_EVENT_FNKEY_F8 },
+	{ 0x19, SONYPI_EVENT_FNKEY_F9 },
+	{ 0x1a, SONYPI_EVENT_FNKEY_F10 },
+	{ 0x1b, SONYPI_EVENT_FNKEY_F11 },
+	{ 0x1c, SONYPI_EVENT_FNKEY_F12 },
+	{ 0x21, SONYPI_EVENT_FNKEY_1 },
+	{ 0x22, SONYPI_EVENT_FNKEY_2 },
+	{ 0x31, SONYPI_EVENT_FNKEY_D },
+	{ 0x32, SONYPI_EVENT_FNKEY_E },
+	{ 0x33, SONYPI_EVENT_FNKEY_F },
+	{ 0x34, SONYPI_EVENT_FNKEY_S },
+	{ 0x35, SONYPI_EVENT_FNKEY_B },
+	{ 0x00, 0x00 }
+};
+
+/* The set of possible bluetooth events */
+static struct sonypi_event sonypi_blueev[] = {
+	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+	{ 0x00, 0x00 }
+};
+
+#define SONYPI_BUF_SIZE	128
+struct sonypi_queue {
+	unsigned long head;
+	unsigned long tail;
+	unsigned long len;
+	spinlock_t s_lock;
+	wait_queue_head_t proc_list;
+	struct fasync_struct *fasync;
+	unsigned char buf[SONYPI_BUF_SIZE];
+};
+
+#define SONYPI_DEVICE_MODEL_NORMAL	1
+#define SONYPI_DEVICE_MODEL_R505	2
+
+struct sonypi_device {
+	struct pci_dev *dev;
+	u16 irq;
+	u16 bits;
+	u16 ioport1;
+	u16 ioport2;
+	u16 region_size;
+	int camera_power;
+	struct semaphore lock;
+	struct sonypi_queue queue;
+	int open_count;
+	int model;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _SONYPI_PRIV_H_ */
diff -u --recursive --new-file v2.4.6/linux/drivers/char/sx.c linux/drivers/char/sx.c
--- v2.4.6/linux/drivers/char/sx.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/char/sx.c	Wed Jul  4 14:41:33 2001
@@ -918,7 +918,6 @@
 	                       SP_DCEN);
 
 	sx_write_channel_byte (port, hi_break, 
-	                       I_OTHER(port->gs.tty) ? 0:
 	                       (I_IGNBRK(port->gs.tty)?BR_IGN:0 |
 	                        I_BRKINT(port->gs.tty)?BR_INT:0));
 
@@ -1140,9 +1139,7 @@
 		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
 
 		sx_write_channel_byte (port, hi_state, hi_state);
-		if (port->gs.flags & ASYNC_SAK) {
-			do_SAK (port->gs.tty);
-		}
+		gs_got_break (port);
 	}
 	if (hi_state & ST_DCD) {
 		hi_state &= ~ST_DCD;
diff -u --recursive --new-file v2.4.6/linux/drivers/char/w83877f_wdt.c linux/drivers/char/w83877f_wdt.c
--- v2.4.6/linux/drivers/char/w83877f_wdt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/w83877f_wdt.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,347 @@
+/*
+ *	W83877F Computer Watchdog Timer driver for Linux 2.4.x
+ *
+ *      Based on acquirewdt.c by Alan Cox,
+ *           and sbc60xxwdt.c by Jakob Oestergaard <jakob@ostenfeld.dk>
+ *     
+ *	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 authors do NOT admit liability nor provide warranty for 
+ *	any of this software. This material is provided "AS-IS" in 
+ *      the hope that it may be useful for others.
+ *
+ *	(c) Copyright 2001    Scott Jennings <management@oro.net>
+ *
+ *           4/19 - 2001      [Initial revision]
+ *
+ *
+ *  Theory of operation:
+ *  A Watchdog Timer (WDT) is a hardware circuit that can 
+ *  reset the computer system in case of a software fault.
+ *  You probably knew that already.
+ *
+ *  Usually a userspace daemon will notify the kernel WDT driver
+ *  via the /proc/watchdog special device file that userspace is
+ *  still alive, at regular intervals.  When such a notification
+ *  occurs, the driver will usually tell the hardware watchdog
+ *  that everything is in order, and that the watchdog should wait
+ *  for yet another little while to reset the system.
+ *  If userspace fails (RAM error, kernel bug, whatever), the
+ *  notifications cease to occur, and the hardware watchdog will
+ *  reset the system (causing a reboot) after the timeout occurs.
+ *
+ *  This WDT driver is different from most other Linux WDT
+ *  drivers in that the driver will ping the watchdog by itself,
+ *  because this particular WDT has a very short timeout (1.6
+ *  seconds) and it would be insane to count on any userspace
+ *  daemon always getting scheduled within that time frame.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.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>
+
+#define OUR_NAME "w83877f_wdt"
+
+#define ENABLE_W83877F_PORT 0x3F0
+#define ENABLE_W83877F 0x87
+#define DISABLE_W83877F 0xAA
+#define WDT_PING 0x443
+#define WDT_REGISTER 0x14
+#define WDT_ENABLE 0x9C
+#define WDT_DISABLE 0x8C
+
+/*
+ * The W83877F seems to be fixed at 1.6s timeout (at least on the
+ * EMACS PC-104 board I'm using). If we reset the watchdog every
+ * ~250ms we should be safe.  */
+
+#define WDT_INTERVAL (HZ/4+1)
+
+/*
+ * We must not require too good response from the userspace daemon.
+ * Here we require the userspace daemon to send us a heartbeat
+ * char to /dev/watchdog every 30 seconds.
+ */
+
+#define WDT_HEARTBEAT (HZ * 30)
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static int wdt_is_open;
+static int wdt_expect_close;
+
+/*
+ *	Whack the dog
+ */
+
+static void wdt_timer_ping(unsigned long data)
+{
+	/* If we got a heartbeat pulse within the WDT_US_INTERVAL
+	 * we agree to ping the WDT 
+	 */
+	if(time_before(jiffies, next_heartbeat)) 
+	{
+		/* Ping the WDT by reading from WDT_PING */
+		inb_p(WDT_PING);
+		/* Re-set the timer interval */
+		timer.expires = jiffies + WDT_INTERVAL;
+		add_timer(&timer);
+	} else {
+		printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+/* 
+ * Utility routines
+ */
+
+static void wdt_change(int writeval)
+{
+	/* buy some time */
+	inb_p(WDT_PING);
+
+	/* make W83877F available */
+	outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT);
+	outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT);
+
+	/* enable watchdog */
+	outb_p(WDT_REGISTER,ENABLE_W83877F_PORT);
+	outb_p(writeval,ENABLE_W83877F_PORT+1);
+
+	/* lock the W8387FF away */
+	outb_p(DISABLE_W83877F,ENABLE_W83877F_PORT);
+}
+
+static void wdt_startup(void)
+{
+	next_heartbeat = jiffies + WDT_HEARTBEAT;
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;	
+	add_timer(&timer);
+
+	wdt_change(WDT_ENABLE);
+
+	printk(OUR_NAME ": Watchdog timer is now enabled.\n");  
+}
+
+static void wdt_turnoff(void)
+{
+	/* Stop the timer */
+	del_timer(&timer);
+
+	wdt_change(WDT_DISABLE);
+
+	printk(OUR_NAME ": Watchdog timer is now disabled...\n");
+}
+
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos)
+{
+	/* We can't seek */
+	if(ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* See if we got the magic character */
+	if(count) 
+	{
+		size_t ofs;
+
+		/* note: just in case someone wrote the magic character
+		 * five months ago... */
+		wdt_expect_close = 0;
+
+		/* now scan */
+		for(ofs = 0; ofs != count; ofs++)
+		  if(buf[ofs] == 'V')
+				wdt_expect_close = 1;
+
+		/* someone wrote to us, we should restart timer */
+		next_heartbeat = jiffies + WDT_HEARTBEAT;
+		return 1;
+	};
+	return 0;
+}
+
+static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos)
+{
+	/* No can do */
+	return -EINVAL;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	switch(MINOR(inode->i_rdev)) 
+	{
+		case WATCHDOG_MINOR:
+			/* Just in case we're already talking to someone... */
+			if(wdt_is_open)
+				return -EBUSY;
+			/* Good, fire up the show */
+			wdt_is_open = 1;
+			wdt_startup();
+			return 0;
+
+		default:
+			return -ENODEV;
+	}
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+	lock_kernel();
+	if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) 
+	{
+		if(wdt_expect_close)
+			wdt_turnoff();
+		else {
+			del_timer(&timer);
+			printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
+		}
+	}
+	wdt_is_open = 0;
+	unlock_kernel();
+	return 0;
+}
+
+static long long fop_llseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	static struct watchdog_info ident=
+	{
+		0,
+		1,
+		"W83877F"
+	};
+	
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_KEEPALIVE:
+			next_heartbeat = jiffies + WDT_HEARTBEAT;
+			return 0;
+	}
+}
+
+static struct file_operations wdt_fops = {
+	owner:		THIS_MODULE,
+	llseek:		fop_llseek,
+	read:		fop_read,
+	write:		fop_write,
+	open:		fop_open,
+	release:	fop_close,
+	ioctl:		fop_ioctl
+};
+
+static struct miscdevice wdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&wdt_fops
+};
+
+/*
+ *	Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) 
+		wdt_turnoff();
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block wdt_notifier=
+{
+	wdt_notify_sys,
+	0,
+	0
+};
+
+static void __exit w83877f_wdt_unload(void)
+{
+	wdt_turnoff();
+
+	/* Deregister */
+	misc_deregister(&wdt_miscdev);
+
+	unregister_reboot_notifier(&wdt_notifier);
+	release_region(WDT_PING,1);
+	release_region(ENABLE_W83877F_PORT,2);
+}
+
+static int __init w83877f_wdt_init(void)
+{
+	int rc = -EBUSY;
+
+	if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT"))
+		goto err_out;
+	if (!request_region(WDT_PING, 1, "W8387FF WDT"))
+		goto err_out_region1;
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 0;
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc)
+		goto err_out_region2;
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc)
+		goto err_out_miscdev;
+
+	printk(KERN_INFO OUR_NAME ": WDT driver for W83877F initialised.\n");
+	
+	return 0;
+
+err_out_miscdev:
+	misc_deregister(&wdt_miscdev);
+err_out_region2:
+	release_region(WDT_PING,1);
+err_out_region1:
+	release_region(ENABLE_W83877F_PORT,2);
+err_out:
+	return rc;
+}
+
+module_init(w83877f_wdt_init);
+module_exit(w83877f_wdt_unload);
diff -u --recursive --new-file v2.4.6/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- v2.4.6/linux/drivers/ide/ide-tape.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/ide/ide-tape.c	Wed Jul  4 14:41:33 2001
@@ -1454,7 +1454,7 @@
 		case IDETAPE_WRITE_FILEMARK_CMD:	return("WRITE_FILEMARK_CMD");
 		case IDETAPE_SPACE_CMD:			return("SPACE_CMD");
 		case IDETAPE_INQUIRY_CMD:		return("INQUIRY_CMD");
-		case IDETAPE_ERASE_CMD:			return("ERASE_CMD")
+		case IDETAPE_ERASE_CMD:			return("ERASE_CMD");
 		case IDETAPE_MODE_SENSE_CMD:		return("MODE_SENSE_CMD");
 		case IDETAPE_MODE_SELECT_CMD:		return("MODE_SELECT_CMD");
 		case IDETAPE_LOAD_UNLOAD_CMD:		return("LOAD_UNLOAD_CMD");
diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h
--- v2.4.6/linux/drivers/isdn/eicon/eicon.h	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/eicon/eicon.h	Fri Jul  6 17:01:06 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.23.6.3 2001/05/17 21:15:33 kai Exp $
+/* $Id: eicon.h,v 1.23.6.4 2001/06/09 15:14:16 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.4.6/linux/drivers/isdn/hisax/config.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/hisax/config.c	Fri Jul  6 17:01:45 2001
@@ -56,8 +56,8 @@
  *   26 AVM A1 PCMCIA (Fritz)   p0=irq p1=iobase
  *   27 AVM PnP/PCI 		p0=irq p1=iobase (PCI no parameter)
  *   28 Sedlbauer Speed Fax+ 	p0=irq p1=iobase (from isapnp setup)
- *   29 Siemens I-Surf          p0=irq p1=iobase p2=memory (from isapnp setup)   
- *   30 ACER P10                p0=irq p1=iobase (from isapnp setup)   
+ *   29 Siemens I-Surf          p0=irq p1=iobase p2=memory (from isapnp setup)
+ *   30 ACER P10                p0=irq p1=iobase (from isapnp setup)
  *   31 HST Saphir              p0=irq  p1=iobase
  *   32 Telekom A4T             none
  *   33 Scitel Quadro		p0=subcontroller (4*S0, subctrl 1...4)
@@ -73,16 +73,18 @@
  *
  */
 
-const char *CardType[] =
-{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP",
- "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
- "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
- "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
- "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
- "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
- "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
- "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
- "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+const char *CardType[] = {
+	"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
+	"Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep",
+	"Teles PCMCIA",	"ITK ix1-micro Rev.2", "Elsa PCMCIA",
+	"Eicon.Diehl Diva", "ISDNLink",	"TeleInt", "Teles 16.3c",
+	"Sedlbauer Speed Card", "USR Sportster", "ith mic Linux",
+	"Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI", 
+	"Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box",
+	"AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +",
+	"Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
+	"Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+	"HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
 };
 
 void HiSax_closecard(int cardnr);
@@ -90,9 +92,9 @@
 #ifdef CONFIG_HISAX_ELSA
 #define DEFAULT_CARD ISDN_CTYPE_ELSA
 #define DEFAULT_CFG {0,0,0,0}
-int elsa_init_pcmcia(void*, int, int*, int);
+int elsa_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(elsa_init_pcmcia);
-#endif /* CONFIG_HISAX_ELSA */
+#endif
 
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
@@ -106,9 +108,9 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
 #define DEFAULT_CFG {11,0x170,0,0}
-int avm_a1_init_pcmcia(void*, int, int*, int);
+int avm_a1_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(avm_a1_init_pcmcia);
-#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */
+#endif
 
 #ifdef CONFIG_HISAX_FRITZPCI
 #undef DEFAULT_CARD
@@ -178,9 +180,9 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
 #define DEFAULT_CFG {11,0x270,0,0}
-int sedl_init_pcmcia(void*, int, int*, int);
+int sedl_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(sedl_init_pcmcia);
-#endif /* CONFIG_HISAX_SEDLBAUER */
+#endif
 
 #ifdef CONFIG_HISAX_SPORTSTER
 #undef DEFAULT_CARD
@@ -222,7 +224,7 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_HFC_SX
 #define DEFAULT_CFG {5,0x2E0,0,0}
-int hfc_init_pcmcia(void*, int, int*, int);
+int hfc_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(hfc_init_pcmcia);
 #endif
 
@@ -255,7 +257,7 @@
 #define DEFAULT_CFG {5,0x250,0,0}
 #endif
 
-#ifdef CONFIG_HISAX_BKM_A4T            
+#ifdef CONFIG_HISAX_BKM_A4T
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_BKM_A4T
@@ -327,8 +329,7 @@
 
 #define EMPTY_CARD	{0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
 
-struct IsdnCard cards[] =
-{
+struct IsdnCard cards[] = {
 	FIRST_CARD,
 	EMPTY_CARD,
 	EMPTY_CARD,
@@ -373,7 +374,7 @@
 #ifdef IO0_IO1
 MODULE_PARM(io0, "1-8i");
 MODULE_PARM(io1, "1-8i");
-#endif /* IO0_IO1 */
+#endif
 #endif /* MODULE */
 
 int nrcards;
@@ -384,8 +385,7 @@
 extern char *lli_revision;
 extern char *tei_revision;
 
-char *
-HiSax_getrev(const char *revision)
+char *HiSax_getrev(const char *revision)
 {
 	char *rev;
 	char *p;
@@ -399,8 +399,7 @@
 	return rev;
 }
 
-void __init
-HiSaxVersion(void)
+void __init HiSaxVersion(void)
 {
 	char tmp[64];
 
@@ -419,26 +418,24 @@
 	strcpy(tmp, l3_revision);
 	printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
 	strcpy(tmp, lli_revision);
-	printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp));
+	printk(KERN_INFO "HiSax: LinkLayer Revision %s\n",
+	       HiSax_getrev(tmp));
 	certification_check(1);
 }
 
-void
-HiSax_mod_dec_use_count(void)
+void HiSax_mod_dec_use_count(void)
 {
 	MOD_DEC_USE_COUNT;
 }
 
-void
-HiSax_mod_inc_use_count(void)
+void HiSax_mod_inc_use_count(void)
 {
 	MOD_INC_USE_COUNT;
 }
 
 #ifndef MODULE
 #define MAX_ARG	(HISAX_MAX_CARDS*5)
-static int __init
-HiSax_setup(char *line)
+static int __init HiSax_setup(char *line)
 {
 	int i, j, argc;
 	int ints[MAX_ARG + 1];
@@ -446,7 +443,7 @@
 
 	str = get_options(line, MAX_ARG, ints);
 	argc = ints[0];
-	printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str);
+	printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str);
 	i = 0;
 	j = 1;
 	while (argc && (i < HISAX_MAX_CARDS)) {
@@ -484,7 +481,7 @@
 		strcpy(HiSaxID, "HiSax");
 		HiSax_id = HiSaxID;
 	}
-	return(1);
+	return 1;
 }
 
 __setup("hisax=", HiSax_setup);
@@ -527,7 +524,7 @@
 #endif
 
 #if CARD_DIEHLDIVA
-extern	int  setup_diva(struct IsdnCard *card);
+extern int setup_diva(struct IsdnCard *card);
 #endif
 
 #if CARD_ASUSCOM
@@ -609,43 +606,41 @@
 /*
  * Find card with given driverId
  */
-static inline struct IsdnCardState
-*hisax_findcard(int driverid)
+static inline struct IsdnCardState *hisax_findcard(int driverid)
 {
 	int i;
 
 	for (i = 0; i < nrcards; i++)
 		if (cards[i].cs)
 			if (cards[i].cs->myid == driverid)
-				return (cards[i].cs);
-	return (NULL);
+				return cards[i].cs;
+	return NULL;
 }
 
 /*
  * Find card with given card number
  */
-struct IsdnCardState
-*hisax_get_card(int cardnr)
+struct IsdnCardState *hisax_get_card(int cardnr)
 {
-	if ((cardnr <= nrcards) && (cardnr>0))
-		if (cards[cardnr-1].cs)
-			return (cards[cardnr-1].cs);
-	return (NULL);
+	if ((cardnr <= nrcards) && (cardnr > 0))
+		if (cards[cardnr - 1].cs)
+			return cards[cardnr - 1].cs;
+	return NULL;
 }
 
-int
-HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
 {
-	int count,cnt;
+	int count, cnt;
 	u_char *p = buf;
 	struct IsdnCardState *cs = hisax_findcard(id);
 
 	if (cs) {
 		if (len > HISAX_STATUS_BUFSIZE) {
-			printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n",
-				len, HISAX_STATUS_BUFSIZE);
+			printk(KERN_WARNING
+			       "HiSax: status overflow readstat %d/%d\n",
+			       len, HISAX_STATUS_BUFSIZE);
 		}
-		count = cs->status_end - cs->status_read +1;
+		count = cs->status_end - cs->status_read + 1;
 		if (count >= len)
 			count = len;
 		if (user)
@@ -673,13 +668,12 @@
 		return len;
 	} else {
 		printk(KERN_ERR
-		 "HiSax: if_readstatus called with invalid driverId!\n");
+		       "HiSax: if_readstatus called with invalid driverId!\n");
 		return -ENODEV;
 	}
 }
 
-inline int
-jiftime(char *s, long mark)
+static inline int jiftime(char *s, long mark)
 {
 	s += 8;
 
@@ -697,15 +691,15 @@
 	*s-- = mark % 10 + '0';
 	mark /= 10;
 	*s-- = mark % 10 + '0';
-	return(8);
+	return 8;
 }
 
 static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
 
-void
-VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
+		      va_list args)
 {
-/* if head == NULL the fmt contains the full info */
+	/* if head == NULL the fmt contains the full info */
 
 	long flags;
 	int count, i;
@@ -729,18 +723,19 @@
 		len = strlen(fmt);
 	}
 	if (!cs) {
-		printk(KERN_WARNING "HiSax: No CardStatus for message %s", p);
+		printk(KERN_WARNING "HiSax: No CardStatus for message %s",
+		       p);
 		restore_flags(flags);
 		return;
 	}
 	if (len > HISAX_STATUS_BUFSIZE) {
 		printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
-			len, HISAX_STATUS_BUFSIZE);
+		       len, HISAX_STATUS_BUFSIZE);
 		restore_flags(flags);
 		return;
 	}
 	count = len;
-	i = cs->status_end - cs->status_write +1;
+	i = cs->status_end - cs->status_write + 1;
 	if (i >= len)
 		i = len;
 	len -= i;
@@ -754,7 +749,7 @@
 		cs->status_write += len;
 	}
 #ifdef KERNELSTACK_DEBUG
-	i = (ulong)&len - current->kernel_stack_page;
+	i = (ulong) & len - current->kernel_stack_page;
 	sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
 		current->kernel_stack_page, i);
 	len = strlen(tmpbuf);
@@ -774,8 +769,7 @@
 	}
 }
 
-void
-HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
 {
 	va_list args;
 
@@ -784,8 +778,7 @@
 	va_end(args);
 }
 
-int
-ll_run(struct IsdnCardState *cs, int addfeatures)
+int ll_run(struct IsdnCardState *cs, int addfeatures)
 {
 	long flags;
 	isdn_ctrl ic;
@@ -800,19 +793,17 @@
 	return 0;
 }
 
-void
-ll_stop(struct IsdnCardState *cs)
+void ll_stop(struct IsdnCardState *cs)
 {
 	isdn_ctrl ic;
 
 	ic.command = ISDN_STAT_STOP;
 	ic.driver = cs->myid;
 	cs->iif.statcallb(&ic);
-//	CallcFreeChan(cs);
+	//      CallcFreeChan(cs);
 }
 
-static void
-ll_unload(struct IsdnCardState *cs)
+static void ll_unload(struct IsdnCardState *cs)
 {
 	isdn_ctrl ic;
 
@@ -827,8 +818,7 @@
 	kfree(cs->dlog);
 }
 
-static void
-closecard(int cardnr)
+static void closecard(int cardnr)
 {
 	struct IsdnCardState *csta = cards[cardnr].cs;
 
@@ -856,56 +846,54 @@
 	ll_unload(csta);
 }
 
-static int __devinit
-init_card(struct IsdnCardState *cs)
+static int __devinit init_card(struct IsdnCardState *cs)
 {
 	int irq_cnt, cnt = 3;
 	long flags;
 
 	if (!cs->irq)
-		return(cs->cardmsg(cs, CARD_INIT, NULL));
+		return cs->cardmsg(cs, CARD_INIT, NULL);
 	save_flags(flags);
 	cli();
 	irq_cnt = kstat_irqs(cs->irq);
-	printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
-		irq_cnt);
+	printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+	       cs->irq, irq_cnt);
 	if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
 		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
-			cs->irq);
+		       cs->irq);
 		restore_flags(flags);
-		return(1);
+		return 1;
 	}
 	while (cnt) {
 		cs->cardmsg(cs, CARD_INIT, NULL);
 		sti();
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		/* Timeout 10ms */
-		schedule_timeout((10*HZ)/1000);
+		schedule_timeout((10 * HZ) / 1000);
 		restore_flags(flags);
-		printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
-			cs->irq, kstat_irqs(cs->irq));
+		printk(KERN_INFO "%s: IRQ %d count %d\n",
+		       CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
 		if (kstat_irqs(cs->irq) == irq_cnt) {
 			printk(KERN_WARNING
 			       "%s: IRQ(%d) getting no interrupts during init %d\n",
 			       CardType[cs->typ], cs->irq, 4 - cnt);
 			if (cnt == 1) {
 				free_irq(cs->irq, cs);
-				return (2);
+				return 2;
 			} else {
 				cs->cardmsg(cs, CARD_RESET, NULL);
 				cnt--;
 			}
 		} else {
 			cs->cardmsg(cs, CARD_TEST, NULL);
-			return(0);
+			return 0;
 		}
 	}
 	restore_flags(flags);
-	return(3);
+	return 3;
 }
 
-static int __devinit
-checkcard(int cardnr, char *id, int *busy_flag)
+static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
 {
 	long flags;
 	int ret = 0;
@@ -923,8 +911,8 @@
 	}
 	memset(cs, 0, sizeof(struct IsdnCardState));
 	card->cs = cs;
-	cs->chanlimit = 2; /* maximum B-channel number */
-	cs->logecho = 0; /* No echo logging */
+	cs->chanlimit = 2;	/* maximum B-channel number */
+	cs->logecho = 0;	/* No echo logging */
 	cs->cardnr = cardnr;
 	cs->debug = L1_DEB_WARN;
 	cs->HW_Flags = 0;
@@ -940,14 +928,12 @@
 
 	if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
 		printk(KERN_WARNING
-		       "HiSax: Card Type %d out of range\n",
-		       card->typ);
+		       "HiSax: Card Type %d out of range\n", card->typ);
 		goto outf_cs;
 	}
 	if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
 		printk(KERN_WARNING
-		       "HiSax: No memory for dlog(card %d)\n",
-		       cardnr + 1);
+		       "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
 		goto outf_cs;
 	}
 	if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
@@ -981,7 +967,7 @@
 		ISDN_FEATURE_P_NI1 |
 #endif
 		0;
-	
+
 	cs->iif.command = HiSax_command;
 	cs->iif.writecmd = NULL;
 	cs->iif.writebuf_skb = HiSax_writebuf_skb;
@@ -1092,12 +1078,12 @@
 		break;
 #endif
 #if CARD_HFC_PCI
-	case ISDN_CTYPE_HFC_PCI: 
+	case ISDN_CTYPE_HFC_PCI:
 		ret = setup_hfcpci(card);
 		break;
 #endif
 #if CARD_HFC_SX
-	case ISDN_CTYPE_HFC_SX: 
+	case ISDN_CTYPE_HFC_SX:
 		ret = setup_hfcsx(card);
 		break;
 #endif
@@ -1126,7 +1112,7 @@
 		ret = setup_testemu(card);
 		break;
 #endif
-#if	CARD_BKM_A4T       
+#if	CARD_BKM_A4T
 	case ISDN_CTYPE_BKM_A4T:
 		ret = setup_bkm_a4t(card);
 		break;
@@ -1163,8 +1149,7 @@
 		goto outf_cs;
 	}
 	if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for isac rcvbuf\n");
+		printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
 		ll_unload(cs);
 		goto outf_cs;
 	}
@@ -1210,8 +1195,7 @@
 	return ret;
 }
 
-void __devinit
-HiSax_shiftcards(int idx)
+void __devinit HiSax_shiftcards(int idx)
 {
 	int i;
 
@@ -1219,8 +1203,7 @@
 		memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-int __devinit
-HiSax_inithardware(int *busy_flag)
+int __devinit HiSax_inithardware(int *busy_flag)
 {
 	int foundcards = 0;
 	int i = 0;
@@ -1254,7 +1237,8 @@
 			foundcards++;
 			i++;
 		} else {
-			printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+			printk(KERN_WARNING
+			       "HiSax: Card %s not installed !\n",
 			       CardType[cards[i].typ]);
 			HiSax_shiftcards(i);
 			nrcards--;
@@ -1263,19 +1247,17 @@
 	return foundcards;
 }
 
-void
-HiSax_closecard(int cardnr)
+void HiSax_closecard(int cardnr)
 {
-	int 	i,last=nrcards - 1;
+	int i, last = nrcards - 1;
 
-	if (cardnr>last)
+	if (cardnr > last)
 		return;
 	if (cards[cardnr].cs) {
 		ll_stop(cards[cardnr].cs);
 		release_tei(cards[cardnr].cs);
-		
 		CallcFreeChan(cards[cardnr].cs);
-		
+
 		closecard(cardnr);
 		if (cards[cardnr].cs->irq)
 			free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
@@ -1283,15 +1265,14 @@
 		cards[cardnr].cs = NULL;
 	}
 	i = cardnr;
-	while (i!=last) {
-		cards[i] = cards[i+1];
+	while (i <= last) {
+		cards[i] = cards[i + 1];
 		i++;
 	}
 	nrcards--;
 }
 
-void
-HiSax_reportcard(int cardnr, int sel)
+void HiSax_reportcard(int cardnr, int sel)
 {
 	struct IsdnCardState *cs = cards[cardnr].cs;
 
@@ -1299,21 +1280,25 @@
 	printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
 	printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
 	printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
-		(ulong) & HiSax_reportcard);
+	       (ulong) & HiSax_reportcard);
 	printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
 	printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
-		cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
+	       cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
 	printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
-		cs->bcs[0].mode, cs->bcs[0].channel);
+	       cs->bcs[0].mode, cs->bcs[0].channel);
 	printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
-		cs->bcs[1].mode, cs->bcs[1].channel);
+	       cs->bcs[1].mode, cs->bcs[1].channel);
 #ifdef ERROR_STATISTIC
 	printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
-		cs->err_rx, cs->err_crc, cs->err_tx);
-	printk(KERN_DEBUG "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
-		cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, cs->bcs[0].err_tx);
-	printk(KERN_DEBUG "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
-		cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, cs->bcs[1].err_tx);
+	       cs->err_rx, cs->err_crc, cs->err_tx);
+	printk(KERN_DEBUG
+	       "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+	       cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc,
+	       cs->bcs[0].err_tx);
+	printk(KERN_DEBUG
+	       "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+	       cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc,
+	       cs->bcs[1].err_tx);
 	if (sel == 99) {
 		cs->err_rx  = 0;
 		cs->err_crc = 0;
@@ -1333,7 +1318,7 @@
 static int __init HiSax_init(void)
 {
 	int i, retval;
-#ifdef MODULE 
+#ifdef MODULE
 	int j;
 	int nzproto = 0;
 #endif
@@ -1357,7 +1342,7 @@
 
 #ifdef MODULE
 	if (!type[0]) {
-		/* We 'll register drivers later, but init basic functions*/
+		/* We 'll register drivers later, but init basic functions */
 		return 0;
 	}
 #ifdef CONFIG_HISAX_ELSA
@@ -1396,98 +1381,100 @@
 			nzproto++;
 		}
 		switch (type[i]) {
-			case ISDN_CTYPE_16_0:
-				cards[j].para[0] = irq[i];
-				cards[j].para[1] = mem[i];
-				cards[j].para[2] = io[i];
-				break;
+		case ISDN_CTYPE_16_0:
+			cards[j].para[0] = irq[i];
+			cards[j].para[1] = mem[i];
+			cards[j].para[2] = io[i];
+			break;
 
-			case ISDN_CTYPE_8_0:
-				cards[j].para[0] = irq[i];
-				cards[j].para[1] = mem[i];
-				break;
+		case ISDN_CTYPE_8_0:
+			cards[j].para[0] = irq[i];
+			cards[j].para[1] = mem[i];
+			break;
 
 #ifdef IO0_IO1
-			case ISDN_CTYPE_PNP:
-			case ISDN_CTYPE_NICCY:
-				cards[j].para[0] = irq[i];
-				cards[j].para[1] = io0[i];
-				cards[j].para[2] = io1[i];
-				break;
-			case ISDN_CTYPE_COMPAQ_ISA:
-				cards[j].para[0] = irq[i];
-				cards[j].para[1] = io0[i];
-				cards[j].para[2] = io1[i];
-				cards[j].para[3] = io[i];
-				break;
-#endif
-			case ISDN_CTYPE_ELSA:
-			case ISDN_CTYPE_HFC_PCI:
-				cards[j].para[0] = io[i];
-				break;
-			case ISDN_CTYPE_16_3:
-			case ISDN_CTYPE_TELESPCMCIA:
-			case ISDN_CTYPE_A1:
-			case ISDN_CTYPE_A1_PCMCIA:
-			case ISDN_CTYPE_ELSA_PNP:
-			case ISDN_CTYPE_ELSA_PCMCIA:
-			case ISDN_CTYPE_IX1MICROR2:
-			case ISDN_CTYPE_DIEHLDIVA:
-			case ISDN_CTYPE_ASUSCOM:
-			case ISDN_CTYPE_TELEINT:
-			case ISDN_CTYPE_SEDLBAUER:
-			case ISDN_CTYPE_SEDLBAUER_PCMCIA:
-			case ISDN_CTYPE_SEDLBAUER_FAX:
-			case ISDN_CTYPE_SPORTSTER:
-			case ISDN_CTYPE_MIC:
-			case ISDN_CTYPE_TELES3C:
-			case ISDN_CTYPE_ACERP10:
-			case ISDN_CTYPE_S0BOX:
-			case ISDN_CTYPE_FRITZPCI:
-			case ISDN_CTYPE_HSTSAPHIR:
-			case ISDN_CTYPE_GAZEL:
-		        case ISDN_CTYPE_HFC_SX:
-		        case ISDN_CTYPE_HFC_SP_PCMCIA:
-				cards[j].para[0] = irq[i];
-				cards[j].para[1] = io[i];
-				break;
-			case ISDN_CTYPE_ISURF:
+		case ISDN_CTYPE_PNP:
+		case ISDN_CTYPE_NICCY:
+			cards[j].para[0] = irq[i];
+			cards[j].para[1] = io0[i];
+			cards[j].para[2] = io1[i];
+			break;
+		case ISDN_CTYPE_COMPAQ_ISA:
+			cards[j].para[0] = irq[i];
+			cards[j].para[1] = io0[i];
+			cards[j].para[2] = io1[i];
+			cards[j].para[3] = io[i];
+			break;
+#endif
+		case ISDN_CTYPE_ELSA:
+		case ISDN_CTYPE_HFC_PCI:
+			cards[j].para[0] = io[i];
+			break;
+		case ISDN_CTYPE_16_3:
+		case ISDN_CTYPE_TELESPCMCIA:
+		case ISDN_CTYPE_A1:
+		case ISDN_CTYPE_A1_PCMCIA:
+		case ISDN_CTYPE_ELSA_PNP:
+		case ISDN_CTYPE_ELSA_PCMCIA:
+		case ISDN_CTYPE_IX1MICROR2:
+		case ISDN_CTYPE_DIEHLDIVA:
+		case ISDN_CTYPE_ASUSCOM:
+		case ISDN_CTYPE_TELEINT:
+		case ISDN_CTYPE_SEDLBAUER:
+		case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+		case ISDN_CTYPE_SEDLBAUER_FAX:
+		case ISDN_CTYPE_SPORTSTER:
+		case ISDN_CTYPE_MIC:
+		case ISDN_CTYPE_TELES3C:
+		case ISDN_CTYPE_ACERP10:
+		case ISDN_CTYPE_S0BOX:
+		case ISDN_CTYPE_FRITZPCI:
+		case ISDN_CTYPE_HSTSAPHIR:
+		case ISDN_CTYPE_GAZEL:
+		case ISDN_CTYPE_HFC_SX:
+		case ISDN_CTYPE_HFC_SP_PCMCIA:
+			cards[j].para[0] = irq[i];
+			cards[j].para[1] = io[i];
+			break;
+		case ISDN_CTYPE_ISURF:
+			cards[j].para[0] = irq[i];
+			cards[j].para[1] = io[i];
+			cards[j].para[2] = mem[i];
+			break;
+		case ISDN_CTYPE_ELSA_PCI:
+		case ISDN_CTYPE_NETJET_S:
+		case ISDN_CTYPE_AMD7930:
+		case ISDN_CTYPE_TELESPCI:
+		case ISDN_CTYPE_W6692:
+		case ISDN_CTYPE_NETJET_U:
+			break;
+		case ISDN_CTYPE_BKM_A4T:
+			break;
+		case ISDN_CTYPE_SCT_QUADRO:
+			if (irq[i]) {
 				cards[j].para[0] = irq[i];
-				cards[j].para[1] = io[i];
-				cards[j].para[2] = mem[i];
-				break;
-			case ISDN_CTYPE_ELSA_PCI:
-			case ISDN_CTYPE_NETJET_S:
-			case ISDN_CTYPE_AMD7930:
-			case ISDN_CTYPE_TELESPCI:
-			case ISDN_CTYPE_W6692:
-			case ISDN_CTYPE_NETJET_U:
-				break;
-			case ISDN_CTYPE_BKM_A4T:
-	  			break;
-			case ISDN_CTYPE_SCT_QUADRO:
-				if (irq[i]) {
-					cards[j].para[0] = irq[i];
-				} else {
-				        /* QUADRO is a 4 BRI card */
-					cards[j++].para[0] = 1;
-					cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
-					cards[j].protocol = protocol[i];
-					cards[j++].para[0] = 2;
-					cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
-					cards[j].protocol = protocol[i];
-					cards[j++].para[0] = 3;
-					cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
-					cards[j].protocol = protocol[i];
-					cards[j].para[0] = 4;
-				}
-				break;
+			} else {
+				/* QUADRO is a 4 BRI card */
+				cards[j++].para[0] = 1;
+				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+				cards[j].protocol = protocol[i];
+				cards[j++].para[0] = 2;
+				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+				cards[j].protocol = protocol[i];
+				cards[j++].para[0] = 3;
+				cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+				cards[j].protocol = protocol[i];
+				cards[j].para[0] = 4;
+			}
+			break;
 		}
 		j++;
 	}
 	if (!nzproto) {
-		printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
-		printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME);
+		printk(KERN_WARNING
+		       "HiSax: Warning - no protocol specified\n");
+		printk(KERN_WARNING "HiSax: using protocol %s\n",
+		       DEFAULT_PROTO_NAME);
 	}
 #endif
 	if (!HiSax_id)
@@ -1505,7 +1492,7 @@
 		retval = -EIO;
 		goto out_isdnl1;
 	}
-	
+
 	return 0;
 
  out_isdnl1:
@@ -1524,12 +1511,12 @@
 
 static void __exit HiSax_exit(void)
 {
-	int cardnr = nrcards -1;
+	int cardnr = nrcards - 1;
 	long flags;
 
 	save_flags(flags);
 	cli();
-	while(cardnr>=0)
+	while (cardnr >= 0)
 		HiSax_closecard(cardnr--);
 	Isdnl1Free();
 	TeiFree();
@@ -1549,7 +1536,7 @@
 	nrcards = 0;
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
-	   */
+	*/
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].para[0] = irq[i];
 		cards[i].para[1] = io[i];
@@ -1559,7 +1546,7 @@
 		}
 	}
 	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int)pcm_iob;
+	cards[0].para[1] = (int) pcm_iob;
 	cards[0].protocol = prot;
 	cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA;
 
@@ -1576,7 +1563,7 @@
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-	return (0);
+	return 0;
 }
 #endif
 
@@ -1590,7 +1577,7 @@
 	nrcards = 0;
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
-	   */
+	*/
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].para[0] = irq[i];
 		cards[i].para[1] = io[i];
@@ -1601,7 +1588,7 @@
 		}
 	}
 	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int)pcm_iob;
+	cards[0].para[1] = (int) pcm_iob;
 	cards[0].protocol = prot;
 	cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA;
 	nzproto = 1;
@@ -1619,7 +1606,7 @@
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-	return (0);
+	return 0;
 }
 #endif
 
@@ -1633,7 +1620,7 @@
 	nrcards = 0;
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
-	   */
+	*/
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].para[0] = irq[i];
 		cards[i].para[1] = io[i];
@@ -1644,7 +1631,7 @@
 		}
 	}
 	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int)pcm_iob;
+	cards[0].para[1] = (int) pcm_iob;
 	cards[0].protocol = prot;
 	cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
 	nzproto = 1;
@@ -1662,7 +1649,7 @@
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-	return (0);
+	return 0;
 }
 #endif
 
@@ -1676,7 +1663,7 @@
 	nrcards = 0;
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
-	   */
+	*/
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].para[0] = irq[i];
 		cards[i].para[1] = io[i];
@@ -1687,7 +1674,7 @@
 		}
 	}
 	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int)pcm_iob;
+	cards[0].para[1] = (int) pcm_iob;
 	cards[0].protocol = prot;
 	cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
 	nzproto = 1;
@@ -1705,11 +1692,12 @@
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-	return (0);
+	return 0;
 }
 #endif
 
-int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag,
+				struct IsdnCard *card)
 {
 	u_char ids[16];
 	int ret = -1;
@@ -1720,11 +1708,11 @@
 	else
 		sprintf(ids, "HiSax");
 	if (!checkcard(nrcards, ids, busy_flag)) {
-		return(-1);
+		return -1;
 	}
 	ret = nrcards;
 	nrcards++;
-	return (ret);
+	return ret;
 }
 
 #include <linux/pci.h>
diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/md linux/drivers/isdn/hisax/md
--- v2.4.6/linux/drivers/isdn/hisax/md	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/hisax/md	Wed Dec 31 16:00:00 1969
@@ -1,12 +0,0 @@
-6f9433a8b696076562562d090e3c420f  isac.c
-13c3eed869f5139f44c563e3a8fea1f5  isdnl1.c
-addcff863b0ff1e366c0f2ae9fa6e81e  isdnl2.c
-7076deb94a363945c21ea27aca4a720a  isdnl3.c
-51c603829b6cc4f8421f744ad657ceff  tei.c
-669050ab5079f02887ed0239d86e5474  callc.c
-e592db58630c1f1029cc064110108156  cert.c
-fadeb3b85bb23bc1ac48470c0848d6fa  l3dss1.c
-cf7dec9fac6283716904d26b99188476  l3_1tr6.c
-65d9e5471bc129624f858ebcf0743525  elsa.c
-b4cf8a4dceed9ea6dcba65a85b4eecc7  diva.c
-99e67bea8f6945fa0d4e0aded5bf0fa0  sedlbauer.c
diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.4.6/linux/drivers/isdn/isdn_tty.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/isdn_tty.c	Fri Jul  6 17:01:06 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.94.6.2 2001/06/09 15:14:15 kai Exp $
+/* $Id: isdn_tty.c,v 1.94.6.3 2001/07/03 14:48:25 kai Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -66,7 +66,7 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.94.6.2 $";
+char *isdn_tty_revision = "$Revision: 1.94.6.3 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -1420,8 +1420,7 @@
 	status = info->lsr;
 	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	put_user(result, (uint *) value);
-	return 0;
+	return put_user(result, (uint *) value);
 }
 
 
@@ -1444,8 +1443,7 @@
 	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
 	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
 	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	put_user(result, (uint *) value);
-	return 0;
+	return put_user(result, (uint *) value);
 }
 
 static int
@@ -1454,7 +1452,8 @@
 	uint arg;
 	int pre_dtr;
 
-	get_user(arg, (uint *) value);
+	if (get_user(arg, (uint *) value))
+		return -EFAULT;
 	switch (cmd) {
 		case TIOCMBIS:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
@@ -1522,7 +1521,6 @@
 	       uint cmd, ulong arg)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
-	int error;
 	int retval;
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
@@ -1552,19 +1550,13 @@
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
 #endif
-			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-			if (error)
-				return error;
-			put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
-			return 0;
+			return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
 		case TIOCSSOFTCAR:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
 #endif
-			error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
-			if (error)
-				return error;
-			get_user(arg, (ulong *) arg);
+			if (get_user(arg, (ulong *) arg))
+				return -EFAULT;
 			tty->termios->c_cflag =
 			    ((tty->termios->c_cflag & ~CLOCAL) |
 			     (arg ? CLOCAL : 0));
@@ -1573,26 +1565,16 @@
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
 #endif
-			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-			if (error)
-				return error;
 			return isdn_tty_get_modem_info(info, (uint *) arg);
 		case TIOCMBIS:
 		case TIOCMBIC:
 		case TIOCMSET:
-			error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
-			if (error)
-				return error;
 			return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
 		case TIOCSERGETLSR:	/* Get line status register */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
 #endif
-			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-			if (error)
-				return error;
-			else
-				return isdn_tty_get_lsr_info(info, (uint *) arg);
+			return isdn_tty_get_lsr_info(info, (uint *) arg);
 		default:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/Config.in linux/drivers/media/video/Config.in
--- v2.4.6/linux/drivers/media/video/Config.in	Fri Feb 16 16:02:36 2001
+++ linux/drivers/media/video/Config.in	Wed Jul  4 14:41:33 2001
@@ -21,6 +21,13 @@
       dep_tristate '  QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
    fi
 fi
+if [ "$CONFIG_PARPORT" != "n" ]; then
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_PARPORT_1284" != "n" ]; then
+         dep_tristate '  Winbond W9966CF Webcam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+      fi
+   fi
+fi
 dep_tristate '  CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
 if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
   if [ "$CONFIG_PARPORT_1284" != "n" ]; then
@@ -39,7 +46,9 @@
    dep_tristate '  Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI
 fi
 dep_tristate '  Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
-dep_tristate '    Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
 dep_tristate '  Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
+fi
 
 endmenu
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/Makefile linux/drivers/media/video/Makefile
--- v2.4.6/linux/drivers/media/video/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/media/video/Makefile	Wed Jul  4 14:41:33 2001
@@ -38,12 +38,13 @@
 	tda7432.o tda9875.o tuner.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
-obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o 
+obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
 obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o
 obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
 obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o 
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
+obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o saa7110.o saa7111.o saa7185.o adv7175.o bt819.o bt856.o 
 obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
@@ -52,6 +53,7 @@
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
 obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
+obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 # Extract lists of the multi-part drivers.
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c
--- v2.4.6/linux/drivers/media/video/buz.c	Tue Mar  6 19:44:35 2001
+++ linux/drivers/media/video/buz.c	Wed Dec 31 16:00:00 1969
@@ -1,3463 +0,0 @@
-/*
-   buz - Iomega Buz driver version 1.0
-
-   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
-
-   based on
-
-   buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-   and
-
-   bttv - Bt848 frame grabber driver
-
-   Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-   & Marcus Metzler (mocm@thp.uni-koeln.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.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <asm/segment.h>
-#include <linux/types.h>
-#include <linux/wrapper.h>
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-
-#include <linux/videodev.h>
-
-#include <linux/version.h>
-#include <asm/uaccess.h>
-
-#include <linux/i2c-old.h>
-#include "buz.h"
-#include <linux/video_decoder.h>
-#include <linux/video_encoder.h>
-
-#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ )
-#define GPIO_MASK 0xdf
-
-/*
- 
- BUZ
- 
-   GPIO0 = 1, take board out of reset
-   GPIO1 = 1, take JPEG codec out of sleep mode
-   GPIO3 = 1, deassert FRAME# to 36060
-   
-
-   GIRQ0 signals a vertical sync of the video signal
-   GIRQ1 signals that ZR36060's DATERR# line is asserted.
-
-   SAA7111A
-
-   In their infinite wisdom, the Iomega engineers decided to
-   use the same input line for composite and S-Video Color,
-   although there are two entries not connected at all!
-   Through this ingenious strike, it is not possible to
-   keep two running video sources connected at the same time
-   to Composite and S-VHS input!
-
-   mode 0 - N/C
-   mode 1 - S-Video Y
-   mode 2 - noise or something I don't know
-   mode 3 - Composite and S-Video C
-   mode 4 - N/C
-   mode 5 - S-Video (gain C independently selectable of gain Y)
-   mode 6 - N/C
-   mode 7 - S-Video (gain C adapted to gain Y)
- */
-
-#define MAJOR_VERSION 1		/* driver major version */
-#define MINOR_VERSION 0		/* driver minor version */
-
-#define BUZ_NAME      "Iomega BUZ V-1.0"	/* name of the driver */
-
-#define DEBUG(x)		/* Debug driver */
-#define IDEBUG(x)		/* Debug interrupt handler */
-#define IOCTL_DEBUG(x)
-
-
-/* The parameters for this driver */
-
-/*
-   The video mem address of the video card.
-   The driver has a little database for some videocards
-   to determine it from there. If your video card is not in there
-   you have either to give it to the driver as a parameter
-   or set in in a VIDIOCSFBUF ioctl
- */
-
-static unsigned long vidmem;	/* Video memory base address (default 0) */
-
-/* Special purposes only: */
-
-static int triton;		/* 0=no (default), 1=yes */
-static int natoma;		/* 0=no (default), 1=yes */
-
-/*
-   Number and size of grab buffers for Video 4 Linux
-   The vast majority of applications should not need more than 2,
-   the very popular BTTV driver actually does ONLY have 2.
-   Time sensitive applications might need more, the maximum
-   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
-
-   The size is set so that the maximum possible request
-   can be satisfied. Decrease  it, if bigphys_area alloc'd
-   memory is low. If you don't have the bigphys_area patch,
-   set it to 128 KB. Will you allow only to grab small
-   images with V4L, but that's better than nothing.
-
-   v4l_bufsize has to be given in KB !
-
- */
-
-static int v4l_nbufs = 2;
-static int v4l_bufsize = 128;	/* Everybody should be able to work with this setting */
-
-/*
-   Default input and video norm at startup of the driver.
- */
-
-static int default_input;	/* 0=Composite (default), 1=S-VHS */
-static int default_norm;	/* 0=PAL (default), 1=NTSC */
-
-MODULE_PARM(vidmem, "i");
-MODULE_PARM(triton, "i");
-MODULE_PARM(natoma, "i");
-MODULE_PARM(v4l_nbufs, "i");
-MODULE_PARM(v4l_bufsize, "i");
-MODULE_PARM(default_input, "i");
-MODULE_PARM(default_norm, "i");
-
-/* Anybody who uses more than four? */
-#define BUZ_MAX 4
-
-static int zoran_num;		/* number of Buzs in use */
-static struct zoran zoran[BUZ_MAX];
-
-/* forward references */
-
-static void v4l_fbuffer_free(struct zoran *zr);
-static void jpg_fbuffer_free(struct zoran *zr);
-static void zoran_feed_stat_com(struct zoran *zr);
-
-
-
-/*
- *   Allocate the V4L grab buffers
- *
- *   These have to be pysically contiguous.
- *   If v4l_bufsize <= KMALLOC_MAXSIZE we use kmalloc
- */
-
-static int v4l_fbuffer_alloc(struct zoran *zr)
-{
-	int i, off;
-	unsigned char *mem;
-
-	for (i = 0; i < v4l_nbufs; i++) {
-		if (zr->v4l_gbuf[i].fbuffer)
-			printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i);
-
-		if (v4l_bufsize <= KMALLOC_MAXSIZE) {
-			/* Use kmalloc */
-
-			mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL);
-			if (mem == 0) {
-				printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name);
-				v4l_fbuffer_free(zr);
-				return -ENOBUFS;
-			}
-			zr->v4l_gbuf[i].fbuffer = mem;
-			zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
-			zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
-			for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
-				mem_map_reserve(virt_to_page(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;
-		}
-	}
-
-	return 0;
-}
-
-/* free the V4L grab buffers */
-static void v4l_fbuffer_free(struct zoran *zr)
-{
-	int i, off;
-	unsigned char *mem;
-
-	for (i = 0; i < v4l_nbufs; i++) {
-		if (!zr->v4l_gbuf[i].fbuffer)
-			continue;
-
-		mem = zr->v4l_gbuf[i].fbuffer;
-		for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
-			mem_map_unreserve(virt_to_page(mem + off));
-		kfree((void *) zr->v4l_gbuf[i].fbuffer);
-		zr->v4l_gbuf[i].fbuffer = NULL;
-	}
-}
-
-/*
- *   Allocate the MJPEG grab buffers.
- *
- *   If the requested buffer size is smaller than KMALLOC_MAXSIZE,
- *   kmalloc is used to request a physically contiguous area,
- *   else we allocate the memory in framgents with get_free_page.
- *
- *   If a Natoma chipset is present and this is a revision 1 zr36057,
- *   each MJPEG buffer needs to be physically contiguous.
- *   (RJ: This statement is from Dave Perks' original driver,
- *   I could never check it because I have a zr36067)
- *   The driver cares about this because it reduces the buffer
- *   size to KMALLOC_MAXSIZE in that case (which forces contiguous allocation).
- *
- *   RJ: The contents grab buffers needs never be accessed in the driver.
- *       Therefore there is no need to allocate them with vmalloc in order
- *       to get a contiguous virtual memory space.
- *       I don't understand why many other drivers first allocate them with
- *       vmalloc (which uses internally also get_free_page, but delivers you
- *       virtual addresses) and then again have to make a lot of efforts
- *       to get the physical address.
- *
- */
-
-static int jpg_fbuffer_alloc(struct zoran *zr)
-{
-	int i, j, off, alloc_contig;
-	unsigned long mem;
-
-	/* Decide if we should alloc contiguous or fragmented memory */
-	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
-
-	alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE);
-
-	for (i = 0; i < zr->jpg_nbufs; i++) {
-		if (zr->jpg_gbuf[i].frag_tab)
-			printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i);
-
-		/* Allocate fragment table for this buffer */
-
-		mem = get_free_page(GFP_KERNEL);
-		if (mem == 0) {
-			printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i);
-			jpg_fbuffer_free(zr);
-			return -ENOBUFS;
-		}
-		memset((void *) mem, 0, PAGE_SIZE);
-		zr->jpg_gbuf[i].frag_tab = (u32 *) mem;
-		zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem);
-
-		if (alloc_contig) {
-			mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL);
-			if (mem == 0) {
-				jpg_fbuffer_free(zr);
-				return -ENOBUFS;
-			}
-			zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem);
-			zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1;
-			for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
-				mem_map_reserve(virt_to_page(mem + off));
-		} else {
-			/* jpg_bufsize is alreay page aligned */
-			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
-				mem = get_free_page(GFP_KERNEL);
-				if (mem == 0) {
-					jpg_fbuffer_free(zr);
-					return -ENOBUFS;
-				}
-				zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem);
-				zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1;
-				mem_map_reserve(virt_to_page(mem));
-			}
-
-			zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1;
-		}
-	}
-
-	DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n",
-		     (zr->jpg_nbufs * zr->jpg_bufsize) >> 10));
-	zr->jpg_buffers_allocated = 1;
-	return 0;
-}
-
-/* free the MJPEG grab buffers */
-static void jpg_fbuffer_free(struct zoran *zr)
-{
-	int i, j, off, alloc_contig;
-	unsigned char *mem;
-
-	/* Decide if we should alloc contiguous or fragmented memory */
-	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
-
-	alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE);
-
-	for (i = 0; i < zr->jpg_nbufs; i++) {
-		if (!zr->jpg_gbuf[i].frag_tab)
-			continue;
-
-		if (alloc_contig) {
-			if (zr->jpg_gbuf[i].frag_tab[0]) {
-				mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]);
-				for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
-					mem_map_unreserve(virt_to_page(mem + off));
-				kfree((void *) mem);
-				zr->jpg_gbuf[i].frag_tab[0] = 0;
-				zr->jpg_gbuf[i].frag_tab[1] = 0;
-			}
-		} else {
-			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
-				if (!zr->jpg_gbuf[i].frag_tab[2 * j])
-					break;
-				mem_map_unreserve(virt_to_page(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])));
-				free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]));
-				zr->jpg_gbuf[i].frag_tab[2 * j] = 0;
-				zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0;
-			}
-		}
-
-		free_page((unsigned long) zr->jpg_gbuf[i].frag_tab);
-		zr->jpg_gbuf[i].frag_tab = NULL;
-	}
-	zr->jpg_buffers_allocated = 0;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-/* I2C functions                                                           */
-
-#define I2C_DELAY   10
-
-
-/* software I2C functions */
-
-static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data)
-{
-	struct zoran *zr = (struct zoran *) bus->data;
-	btwrite((data << 1) | ctrl, ZR36057_I2CBR);
-	btread(ZR36057_I2CBR);
-	udelay(I2C_DELAY);
-}
-
-static int i2c_getdataline(struct i2c_bus *bus)
-{
-	struct zoran *zr = (struct zoran *) bus->data;
-	return (btread(ZR36057_I2CBR) >> 1) & 1;
-}
-
-static void attach_inform(struct i2c_bus *bus, int id)
-{
-	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
-	DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
-}
-
-static void detach_inform(struct i2c_bus *bus, int id)
-{
-	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
-	DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
-}
-
-static struct i2c_bus zoran_i2c_bus_template = {
-	name:			"zr36057",
-	id:			I2C_BUSID_BT848,
-	bus_lock:		SPIN_LOCK_UNLOCKED,
-
-	attach_inform:		attach_inform,
-	detach_inform:		detach_inform,
-
-	i2c_setlines:		i2c_setlines,
-	i2c_getdataline:	i2c_getdataline,
-};
-
-
-/* ----------------------------------------------------------------------- */
-
-static void GPIO(struct zoran *zr, unsigned bit, unsigned value)
-{
-	u32 reg;
-	u32 mask;
-
-	mask = 1 << (24 + bit);
-	reg = btread(ZR36057_GPPGCR1) & ~mask;
-	if (value) {
-		reg |= mask;
-	}
-	btwrite(reg, ZR36057_GPPGCR1);
-	/* Stop any PCI posting on the GPIO bus */
-	btread(ZR36057_I2CBR);
-}
-
-
-/*
- *   Set the registers for the size we have specified. Don't bother
- *   trying to understand this without the ZR36057 manual in front of
- *   you [AC].
- *
- *   PS: The manual is free for download in .pdf format from
- *   www.zoran.com - nicely done those folks.
- */
-
-struct tvnorm {
-	u16 Wt, Wa, Ht, Ha, HStart, VStart;
-};
-
-static struct tvnorm tvnorms[] =
-{
-   /* PAL-BDGHI */
-	{864, 720, 625, 576, 31, 16},
-   /* NTSC */
-	{858, 720, 525, 480, 21, 8},
-};
-#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm))
-
-static int format2bpp(int format)
-{
-	int bpp;
-
-	/* Determine the number of bytes per pixel for the video format requested */
-
-	switch (format) {
-
-	case VIDEO_PALETTE_YUV422:
-		bpp = 2;
-		break;
-
-	case VIDEO_PALETTE_RGB555:
-		bpp = 2;
-		break;
-
-	case VIDEO_PALETTE_RGB565:
-		bpp = 2;
-		break;
-
-	case VIDEO_PALETTE_RGB24:
-		bpp = 3;
-		break;
-
-	case VIDEO_PALETTE_RGB32:
-		bpp = 4;
-		break;
-
-	default:
-		bpp = 0;
-	}
-
-	return bpp;
-}
-
-/*
- * set geometry
- */
-static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height,
-			    unsigned int video_format)
-{
-	struct tvnorm *tvn;
-	unsigned HStart, HEnd, VStart, VEnd;
-	unsigned DispMode;
-	unsigned VidWinWid, VidWinHt;
-	unsigned hcrop1, hcrop2, vcrop1, vcrop2;
-	unsigned Wa, We, Ha, He;
-	unsigned X, Y, HorDcm, VerDcm;
-	u32 reg;
-	unsigned mask_line_size;
-
-	if (zr->params.norm < 0 || zr->params.norm > 1) {
-		printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name,  zr->params.norm);
-		return;
-	}
-	if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) {
-		printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height);
-		return;
-	}
-	tvn = &tvnorms[zr->params.norm];
-
-	Wa = tvn->Wa;
-	Ha = tvn->Ha;
-
-	/* if window has more than half of active height,
-	   switch on interlacing - we want the full information */
-
-	zr->video_interlace = (video_height > Ha / 2);
-
-/**** zr36057 ****/
-
-	/* horizontal */
-	VidWinWid = video_width;
-	X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
-	We = (VidWinWid * 64) / X;
-	HorDcm = 64 - X;
-	hcrop1 = 2 * ((tvn->Wa - We) / 4);
-	hcrop2 = tvn->Wa - We - hcrop1;
-	HStart = tvn->HStart | 1;
-	HEnd = HStart + tvn->Wa - 1;
-	HStart += hcrop1;
-	HEnd -= hcrop2;
-	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
-	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
-	reg |= ZR36057_VFEHCR_HSPol;
-	btwrite(reg, ZR36057_VFEHCR);
-
-	/* Vertical */
-	DispMode = !zr->video_interlace;
-	VidWinHt = DispMode ? video_height : video_height / 2;
-	Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
-	He = (VidWinHt * 64) / Y;
-	VerDcm = 64 - Y;
-	vcrop1 = (tvn->Ha / 2 - He) / 2;
-	vcrop2 = tvn->Ha / 2 - He - vcrop1;
-	VStart = tvn->VStart;
-	VEnd = VStart + tvn->Ha / 2 - 1;
-	VStart += vcrop1;
-	VEnd -= vcrop2;
-	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
-	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
-	reg |= ZR36057_VFEVCR_VSPol;
-	btwrite(reg, ZR36057_VFEVCR);
-
-	/* scaler and pixel format */
-	reg = 0			// ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */
-	     | (HorDcm << ZR36057_VFESPFR_HorDcm)
-	    | (VerDcm << ZR36057_VFESPFR_VerDcm)
-	    | (DispMode << ZR36057_VFESPFR_DispMode)
-	    | ZR36057_VFESPFR_LittleEndian;
-	/* RJ: I don't know, why the following has to be the opposite
-	   of the corresponding ZR36060 setting, but only this way
-	   we get the correct colors when uncompressing to the screen  */
-	reg |= ZR36057_VFESPFR_VCLKPol;
-	/* RJ: Don't know if that is needed for NTSC also */
-	reg |= ZR36057_VFESPFR_TopField;
-	switch (video_format) {
-
-	case VIDEO_PALETTE_YUV422:
-		reg |= ZR36057_VFESPFR_YUV422;
-		break;
-
-	case VIDEO_PALETTE_RGB555:
-		reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
-		break;
-
-	case VIDEO_PALETTE_RGB565:
-		reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
-		break;
-
-	case VIDEO_PALETTE_RGB24:
-		reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
-		break;
-
-	case VIDEO_PALETTE_RGB32:
-		reg |= ZR36057_VFESPFR_RGB888;
-		break;
-
-	default:
-		printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format);
-		return;
-
-	}
-	if (HorDcm >= 48) {
-		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
-	} else if (HorDcm >= 32) {
-		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */
-	} else if (HorDcm >= 16) {
-		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
-	}
-	btwrite(reg, ZR36057_VFESPFR);
-
-	/* display configuration */
-
-	reg = (16 << ZR36057_VDCR_MinPix)
-	    | (VidWinHt << ZR36057_VDCR_VidWinHt)
-	    | (VidWinWid << ZR36057_VDCR_VidWinWid);
-	if (triton)
-		reg &= ~ZR36057_VDCR_Triton;
-	else
-		reg |= ZR36057_VDCR_Triton;
-	btwrite(reg, ZR36057_VDCR);
-
-	/* Write overlay clipping mask data, but don't enable overlay clipping */
-	/* RJ: since this makes only sense on the screen, we use 
-	   zr->window.width instead of video_width */
-
-	mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
-	reg = virt_to_bus(zr->overlay_mask);
-	btwrite(reg, ZR36057_MMTR);
-	reg = virt_to_bus(zr->overlay_mask + mask_line_size);
-	btwrite(reg, ZR36057_MMBR);
-	reg = mask_line_size - (zr->window.width + 31) / 32;
-	if (DispMode == 0)
-		reg += mask_line_size;
-	reg <<= ZR36057_OCR_MaskStride;
-	btwrite(reg, ZR36057_OCR);
-
-}
-
-/*
- * Switch overlay on or off
- */
-
-static void zr36057_overlay(struct zoran *zr, int on)
-{
-	int fmt, bpp;
-	u32 reg;
-
-	if (on) {
-		/* do the necessary settings ... */
-
-		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */
-
-		switch (zr->buffer.depth) {
-		case 15:
-			fmt = VIDEO_PALETTE_RGB555;
-			bpp = 2;
-			break;
-		case 16:
-			fmt = VIDEO_PALETTE_RGB565;
-			bpp = 2;
-			break;
-		case 24:
-			fmt = VIDEO_PALETTE_RGB24;
-			bpp = 3;
-			break;
-		case 32:
-			fmt = VIDEO_PALETTE_RGB32;
-			bpp = 4;
-			break;
-		default:
-			fmt = 0;
-			bpp = 0;
-		}
-
-		zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt);
-
-		/* Start and length of each line MUST be 4-byte aligned.
-		   This should be allready checked before the call to this routine.
-		   All error messages are internal driver checking only! */
-
-		/* video display top and bottom registers */
-
-		reg = (u32) zr->buffer.base
-		    + zr->window.x * bpp
-		    + zr->window.y * zr->buffer.bytesperline;
-		btwrite(reg, ZR36057_VDTR);
-		if (reg & 3)
-			printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name);
-		if (zr->video_interlace)
-			reg += zr->buffer.bytesperline;
-		btwrite(reg, ZR36057_VDBR);
-
-		/* video stride, status, and frame grab register */
-
-		reg = zr->buffer.bytesperline - zr->window.width * bpp;
-		if (zr->video_interlace)
-			reg += zr->buffer.bytesperline;
-		if (reg & 3)
-			printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name);
-		reg = (reg << ZR36057_VSSFGR_DispStride);
-		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */
-		btwrite(reg, ZR36057_VSSFGR);
-
-		/* Set overlay clipping */
-
-		if (zr->window.clipcount)
-			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
-
-		/* ... and switch it on */
-
-		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
-	} else {
-		/* Switch it off */
-
-		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-	}
-}
-
-/*
- * The overlay mask has one bit for each pixel on a scan line,
- *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
- */
-static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count)
-{
-	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
-	u32 *mask;
-	int x, y, width, height;
-	unsigned i, j, k;
-	u32 reg;
-
-	/* fill mask with one bits */
-	memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
-	reg = 0;
-
-	for (i = 0; i < count; ++i) {
-		/* pick up local copy of clip */
-		x = vp[i].x;
-		y = vp[i].y;
-		width = vp[i].width;
-		height = vp[i].height;
-
-		/* trim clips that extend beyond the window */
-		if (x < 0) {
-			width += x;
-			x = 0;
-		}
-		if (y < 0) {
-			height += y;
-			y = 0;
-		}
-		if (x + width > zr->window.width) {
-			width = zr->window.width - x;
-		}
-		if (y + height > zr->window.height) {
-			height = zr->window.height - y;
-		}
-		/* ignore degenerate clips */
-		if (height <= 0) {
-			continue;
-		}
-		if (width <= 0) {
-			continue;
-		}
-		/* apply clip for each scan line */
-		for (j = 0; j < height; ++j) {
-			/* reset bit for each pixel */
-			/* this can be optimized later if need be */
-			mask = zr->overlay_mask + (y + j) * mask_line_size;
-			for (k = 0; k < width; ++k) {
-				mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32);
-			}
-		}
-	}
-}
-
-/* Enable/Disable uncompressed memory grabbing of the 36057 */
-
-static void zr36057_set_memgrab(struct zoran *zr, int mode)
-{
-	if (mode) {
-		if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
-			printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name);
-
-		/* switch on VSync interrupts */
-
-		btwrite(IRQ_MASK, ZR36057_ISR);		// Clear Interrupts
-
-		btor(ZR36057_ICR_GIRQ0, ZR36057_ICR);
-
-		/* enable SnapShot */
-
-		btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
-
-		/* Set zr36057 video front end  and enable video */
-
-#ifdef XAWTV_HACK
-		zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat);
-#else
-		zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat);
-#endif
-
-		zr->v4l_memgrab_active = 1;
-	} else {
-		zr->v4l_memgrab_active = 0;
-
-		/* switch off VSync interrupts */
-
-		btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR);
-
-		/* reenable grabbing to screen if it was running */
-
-		if (zr->v4l_overlay_active) {
-			zr36057_overlay(zr, 1);
-		} else {
-			btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-			btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
-		}
-	}
-}
-
-static int wait_grab_pending(struct zoran *zr)
-{
-	unsigned long flags;
-
-	/* wait until all pending grabs are finished */
-
-	if (!zr->v4l_memgrab_active)
-		return 0;
-
-	while (zr->v4l_pend_tail != zr->v4l_pend_head) {
-		interruptible_sleep_on(&zr->v4l_capq);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
-
-	spin_lock_irqsave(&zr->lock, flags);
-	zr36057_set_memgrab(zr, 0);
-	spin_unlock_irqrestore(&zr->lock, flags);
-
-	return 0;
-}
-
-/*
- *   V4L Buffer grabbing
- */
-
-static int v4l_grab(struct zoran *zr, struct video_mmap *mp)
-{
-	unsigned long flags;
-	int res, bpp;
-
-	/*
-	 * There is a long list of limitations to what is allowed to be grabbed
-	 * We don't output error messages her, since some programs (e.g. xawtv)
-	 * just try several settings to find out what is valid or not.
-	 */
-
-	/* No grabbing outside the buffer range! */
-
-	if (mp->frame >= v4l_nbufs || mp->frame < 0)
-		return -EINVAL;
-
-	/* Check size and format of the grab wanted */
-
-	if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH)
-		return -EINVAL;
-	if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH)
-		return -EINVAL;
-
-	bpp = format2bpp(mp->format);
-	if (bpp == 0)
-		return -EINVAL;
-
-	/* Check against available buffer size */
-
-	if (mp->height * mp->width * bpp > v4l_bufsize)
-		return -EINVAL;
-
-	/* The video front end needs 4-byte alinged line sizes */
-
-	if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3)))
-		return -EINVAL;
-
-	/*
-	 * To minimize the time spent in the IRQ routine, we avoid setting up
-	 * the video front end there.
-	 * If this grab has different parameters from a running streaming capture
-	 * we stop the streaming capture and start it over again.
-	 */
-
-	if (zr->v4l_memgrab_active &&
-	    (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) {
-		res = wait_grab_pending(zr);
-		if (res)
-			return res;
-	}
-	zr->gwidth = mp->width;
-	zr->gheight = mp->height;
-	zr->gformat = mp->format;
-	zr->gbpl = bpp * zr->gwidth;
-
-
-	spin_lock_irqsave(&zr->lock, flags);
-
-	/* make sure a grab isn't going on currently with this buffer */
-
-	switch (zr->v4l_gbuf[mp->frame].state) {
-
-	default:
-	case BUZ_STATE_PEND:
-		res = -EBUSY;	/* what are you doing? */
-		break;
-
-	case BUZ_STATE_USER:
-	case BUZ_STATE_DONE:
-		/* since there is at least one unused buffer there's room for at least one more pend[] entry */
-		zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame;
-		zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND;
-		res = 0;
-		break;
-
-	}
-
-	/* put the 36057 into frame grabbing mode */
-
-	if (!res && !zr->v4l_memgrab_active)
-		zr36057_set_memgrab(zr, 1);
-
-	spin_unlock_irqrestore(&zr->lock, flags);
-
-	return res;
-}
-
-/*
- * Sync on a V4L buffer
- */
-
-static int v4l_sync(struct zoran *zr, int frame)
-{
-	unsigned long flags;
-
-
-	/* check passed-in frame number */
-	if (frame >= v4l_nbufs || frame < 0) {
-		printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame);
-		return -EINVAL;
-	}
-	/* Check if is buffer was queued at all */
-
-	if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) {
-//		printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name);
-		return -EINVAL;
-	}
-	/* wait on this buffer to get ready */
-
-	while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) {
-		interruptible_sleep_on(&zr->v4l_capq);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
-
-	/* buffer should now be in BUZ_STATE_DONE */
-
-	if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE)
-		printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name);
-
-	/* Check if streaming capture has finished */
-
-	spin_lock_irqsave(&zr->lock, flags);
-
-	if (zr->v4l_pend_tail == zr->v4l_pend_head)
-		zr36057_set_memgrab(zr, 0);
-
-	spin_unlock_irqrestore(&zr->lock, flags);
-
-	return 0;
-}
-/*****************************************************************************
- *                                                                           *
- *  Set up the Buz-specific MJPEG part                                       *
- *                                                                           *
- *****************************************************************************/
-
-/*
- *	Wait til post office is no longer busy 
- */
- 
-static int post_office_wait(struct zoran *zr)
-{
-	u32 por;
-	u32 ct=0;
-
-	while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
-		ct++;
-		if(ct>100000)
-		{
-			printk(KERN_ERR "%s: timeout on post office.\n", zr->name);
-			return -1;
-		}
-		/* wait for something to happen */
-	}
-	if ((por & ZR36057_POR_POPen) != 0) {
-		printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por);
-		return -1;
-	}
-	if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) {
-		printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por);
-		return -1;
-	}
-	return 0;
-}
-
-static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value)
-{
-	u32 por;
-
-	post_office_wait(zr);
-	por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF);
-	btwrite(por, ZR36057_POR);
-	return post_office_wait(zr);
-}
-
-static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg)
-{
-	u32 por;
-
-	post_office_wait(zr);
-	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
-	btwrite(por, ZR36057_POR);
-	if (post_office_wait(zr) < 0) {
-		return -1;
-	}
-	return btread(ZR36057_POR) & 0xFF;
-}
-
-static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val)
-{
-	if (post_office_wait(zr)
-	    || post_office_write(zr, 0, 1, reg >> 8)
-	    || post_office_write(zr, 0, 2, reg)) {
-		return -1;
-	}
-	return post_office_write(zr, 0, 3, val);
-}
-
-static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val)
-{
-	if (zr36060_write_8(zr, reg + 0, val >> 8)) {
-		return -1;
-	}
-	return zr36060_write_8(zr, reg + 1, val >> 0);
-}
-
-static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val)
-{
-	if (zr36060_write_8(zr, reg + 0, val >> 16)) {
-		return -1;
-	}
-	return zr36060_write_16(zr, reg + 1, val >> 0);
-}
-
-static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val)
-{
-	if (zr36060_write_16(zr, reg + 0, val >> 16)) {
-		return -1;
-	}
-	return zr36060_write_16(zr, reg + 2, val >> 0);
-}
-
-static u32 zr36060_read_8(struct zoran *zr, unsigned reg)
-{
-	if (post_office_wait(zr)
-	    || post_office_write(zr, 0, 1, reg >> 8)
-	    || post_office_write(zr, 0, 2, reg)) {
-		return -1;
-	}
-	return post_office_read(zr, 0, 3) & 0xFF;
-}
-
-static int zr36060_reset(struct zoran *zr)
-{
-	return post_office_write(zr, 3, 0, 0);
-}
-
-static void zr36060_sleep(struct zoran *zr, int sleep)
-{
-	GPIO(zr, 1, !sleep);
-}
-
-
-static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
-{
-	struct tvnorm *tvn;
-	u32 reg;
-	int size;
-
-	reg = (1 << 0)		/* CodeMstr */
-	    |(0 << 2)		/* CFIS=0 */
-	    |(0 << 6)		/* Endian=0 */
-	    |(0 << 7);		/* Code16=0 */
-	zr36060_write_8(zr, 0x002, reg);
-
-	switch (mode) {
-
-	case BUZ_MODE_MOTION_DECOMPRESS:
-	case BUZ_MODE_STILL_DECOMPRESS:
-		reg = 0x00;	/* Codec mode = decompression */
-		break;
-
-	case BUZ_MODE_MOTION_COMPRESS:
-	case BUZ_MODE_STILL_COMPRESS:
-	default:
-		reg = 0xa4;	/* Codec mode = compression with variable scale factor */
-		break;
-
-	}
-	zr36060_write_8(zr, 0x003, reg);
-
-	reg = 0x00;		/* reserved, mbz */
-	zr36060_write_8(zr, 0x004, reg);
-
-	reg = 0xff;		/* 510 bits/block */
-	zr36060_write_8(zr, 0x005, reg);
-
-	/* JPEG markers */
-	reg = (zr->params.jpeg_markers) & 0x38;	/* DRI, DQT, DHT */
-	if (zr->params.COM_len)
-		reg |= JPEG_MARKER_COM;
-	if (zr->params.APP_len)
-		reg |= JPEG_MARKER_APP;
-	zr36060_write_8(zr, 0x006, reg);
-
-	reg = (0 << 3)		/* DATERR=0 */
-	    |(0 << 2)		/* END=0 */
-	    |(0 << 1)		/* EOI=0 */
-	    |(0 << 0);		/* EOAV=0 */
-	zr36060_write_8(zr, 0x007, reg);
-
-	/* code volume */
-
-	/* Target field size in pixels: */
-	tvn = &tvnorms[zr->params.norm];
-	size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm);
-
-	/* Target compressed field size in bits: */
-	size = size * 16;	/* uncompressed size in bits */
-	size = size * zr->params.quality / 400;	/* quality = 100 is a compression ratio 1:4 */
-
-	/* Lower limit (arbitrary, 1 KB) */
-	if (size < 8192)
-		size = 8192;
-
-	/* Upper limit: 7/8 of the code buffers */
-	if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7)
-		size = zr->jpg_bufsize * 7 / zr->params.field_per_buff;
-
-	reg = size;
-	zr36060_write_32(zr, 0x009, reg);
-
-	/* how do we set initial SF as a function of quality parameter? */
-	reg = 0x0100;		/* SF=1.0 */
-	zr36060_write_16(zr, 0x011, reg);
-
-	reg = 0x00ffffff;	/* AF=max */
-	zr36060_write_24(zr, 0x013, reg);
-
-	reg = 0x0000;		/* test */
-	zr36060_write_16(zr, 0x024, reg);
-}
-
-static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode)
-{
-	struct tvnorm *tvn;
-	u32 reg;
-
-	reg = (0 << 7)		/* Video8=0 */
-	    |(0 << 6)		/* Range=0 */
-	    |(0 << 3)		/* FlDet=0 */
-	    |(1 << 2)		/* FlVedge=1 */
-	    |(0 << 1)		/* FlExt=0 */
-	    |(0 << 0);		/* SyncMstr=0 */
-
-	/* According to ZR36067 documentation, FlDet should correspond
-	   to the odd_even flag of the ZR36067 */
-	if (zr->params.odd_even)
-		reg |= (1 << 3);
-
-	if (mode != BUZ_MODE_STILL_DECOMPRESS) {
-		/* limit pixels to range 16..235 as per CCIR-601 */
-		reg |= (1 << 6);	/* Range=1 */
-	}
-	zr36060_write_8(zr, 0x030, reg);
-
-	reg = (0 << 7)		/* VCLKPol=0 */
-	    |(0 << 6)		/* PValPol=0 */
-	    |(1 << 5)		/* PoePol=1 */
-	    |(0 << 4)		/* SImgPol=0 */
-	    |(0 << 3)		/* BLPol=0 */
-	    |(0 << 2)		/* FlPol=0 */
-	    |(0 << 1)		/* HSPol=0, sync on falling edge */
-	    |(1 << 0);		/* VSPol=1 */
-	zr36060_write_8(zr, 0x031, reg);
-
-	switch (zr->params.HorDcm) {
-	default:
-	case 1:
-		reg = (0 << 0);
-		break;		/* HScale = 0 */
-
-	case 2:
-		reg = (1 << 0);
-		break;		/* HScale = 1 */
-
-	case 4:
-		reg = (2 << 0);
-		break;		/* HScale = 2 */
-	}
-	if (zr->params.VerDcm == 2)
-		reg |= (1 << 2);
-	zr36060_write_8(zr, 0x032, reg);
-
-	reg = 0x80;		/* BackY */
-	zr36060_write_8(zr, 0x033, reg);
-
-	reg = 0xe0;		/* BackU */
-	zr36060_write_8(zr, 0x034, reg);
-
-	reg = 0xe0;		/* BackV */
-	zr36060_write_8(zr, 0x035, reg);
-
-	/* sync generator */
-
-	tvn = &tvnorms[zr->params.norm];
-
-	reg = tvn->Ht - 1;	/* Vtotal */
-	zr36060_write_16(zr, 0x036, reg);
-
-	reg = tvn->Wt - 1;	/* Htotal */
-	zr36060_write_16(zr, 0x038, reg);
-
-	reg = 6 - 1;		/* VsyncSize */
-	zr36060_write_8(zr, 0x03a, reg);
-
-	reg = 100 - 1;		/* HsyncSize */
-	zr36060_write_8(zr, 0x03b, reg);
-
-	reg = tvn->VStart - 1;	/* BVstart */
-	zr36060_write_8(zr, 0x03c, reg);
-
-	reg += tvn->Ha / 2;	/* BVend */
-	zr36060_write_16(zr, 0x03e, reg);
-
-	reg = tvn->HStart - 1;	/* BHstart */
-	zr36060_write_8(zr, 0x03d, reg);
-
-	reg += tvn->Wa;		/* BHend */
-	zr36060_write_16(zr, 0x040, reg);
-
-	/* active area */
-	reg = zr->params.img_y + tvn->VStart;	/* Vstart */
-	zr36060_write_16(zr, 0x042, reg);
-
-	reg += zr->params.img_height;	/* Vend */
-	zr36060_write_16(zr, 0x044, reg);
-
-	reg = zr->params.img_x + tvn->HStart;	/* Hstart */
-	zr36060_write_16(zr, 0x046, reg);
-
-	reg += zr->params.img_width;	/* Hend */
-	zr36060_write_16(zr, 0x048, reg);
-
-	/* subimage area */
-	reg = zr->params.img_y + tvn->VStart;	/* SVstart */
-	zr36060_write_16(zr, 0x04a, reg);
-
-	reg += zr->params.img_height;	/* SVend */
-	zr36060_write_16(zr, 0x04c, reg);
-
-	reg = zr->params.img_x + tvn->HStart;	/* SHstart */
-	zr36060_write_16(zr, 0x04e, reg);
-
-	reg += zr->params.img_width;	/* SHend */
-	zr36060_write_16(zr, 0x050, reg);
-}
-
-static void zr36060_set_jpg_SOF(struct zoran *zr)
-{
-	u32 reg;
-
-
-	reg = 0xffc0;		/* SOF marker */
-	zr36060_write_16(zr, 0x060, reg);
-
-	reg = 17;		/* SOF length */
-	zr36060_write_16(zr, 0x062, reg);
-
-	reg = 8;		/* precision 8 bits */
-	zr36060_write_8(zr, 0x064, reg);
-
-	reg = zr->params.img_height / zr->params.VerDcm;	/* image height */
-	zr36060_write_16(zr, 0x065, reg);
-
-	reg = zr->params.img_width / zr->params.HorDcm;	/* image width */
-	zr36060_write_16(zr, 0x067, reg);
-
-	reg = 3;		/* 3 color components */
-	zr36060_write_8(zr, 0x069, reg);
-
-	reg = 0x002100;		/* Y component */
-	zr36060_write_24(zr, 0x06a, reg);
-
-	reg = 0x011101;		/* U component */
-	zr36060_write_24(zr, 0x06d, reg);
-
-	reg = 0x021101;		/* V component */
-	zr36060_write_24(zr, 0x070, reg);
-}
-
-static void zr36060_set_jpg_SOS(struct zoran *zr)
-{
-	u32 reg;
-
-
-	reg = 0xffda;		/* SOS marker */
-	zr36060_write_16(zr, 0x07a, reg);
-
-	reg = 12;		/* SOS length */
-	zr36060_write_16(zr, 0x07c, reg);
-
-	reg = 3;		/* 3 color components */
-	zr36060_write_8(zr, 0x07e, reg);
-
-	reg = 0x0000;		/* Y component */
-	zr36060_write_16(zr, 0x07f, reg);
-
-	reg = 0x0111;		/* U component */
-	zr36060_write_16(zr, 0x081, reg);
-
-	reg = 0x0211;		/* V component */
-	zr36060_write_16(zr, 0x083, reg);
-
-	reg = 0x003f00;		/* Start, end spectral scans */
-	zr36060_write_24(zr, 0x085, reg);
-}
-
-static void zr36060_set_jpg_DRI(struct zoran *zr)
-{
-	u32 reg;
-
-
-	reg = 0xffdd;		/* DRI marker */
-	zr36060_write_16(zr, 0x0c0, reg);
-
-	reg = 4;		/* DRI length */
-	zr36060_write_16(zr, 0x0c2, reg);
-
-	reg = 8;		/* length in MCUs */
-	zr36060_write_16(zr, 0x0c4, reg);
-}
-
-static void zr36060_set_jpg_DQT(struct zoran *zr)
-{
-	unsigned i;
-	unsigned adr;
-	static const u8 dqt[] =
-	{
-		0xff, 0xdb,	/* DHT marker */
-		0x00, 0x84,	/* DHT length */
-		0x00,		/* table ID 0 */
-		0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
-		0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
-		0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
-		0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
-		0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
-		0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
-		0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
-		0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
-		0x01,		/* table ID 1 */
-		0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
-		0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
-	};
-
-	/* write fixed quantitization tables */
-	adr = 0x0cc;
-	for (i = 0; i < sizeof(dqt); ++i) {
-		zr36060_write_8(zr, adr++, dqt[i]);
-	}
-}
-
-static void zr36060_set_jpg_DHT(struct zoran *zr)
-{
-	unsigned i;
-	unsigned adr;
-	static const u8 dht[] =
-	{
-		0xff, 0xc4,	/* DHT marker */
-		0x01, 0xa2,	/* DHT length */
-		0x00,		/* table class 0, ID 0 */
-		0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,		/* # codes of length 1..8 */
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,		/* # codes of length 8..16 */
-		0x00,		/* values for codes of length 2 */
-		0x01, 0x02, 0x03, 0x04, 0x05,	/* values for codes of length 3 */
-		0x06,		/* values for codes of length 4 */
-		0x07,		/* values for codes of length 5 */
-		0x08,		/* values for codes of length 6 */
-		0x09,		/* values for codes of length 7 */
-		0x0a,		/* values for codes of length 8 */
-		0x0b,		/* values for codes of length 9 */
-		0x01,		/* table class 0, ID 1 */
-		0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,		/* # codes of length 1..8 */
-		0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,		/* # codes of length 9..16 */
-		0x00, 0x01, 0x02,	/* values for codes of length 2 */
-		0x03,		/* values for codes of length 3 */
-		0x04,		/* values for codes of length 4 */
-		0x05,		/* values for codes of length 5 */
-		0x06,		/* values for codes of length 6 */
-		0x07,		/* values for codes of length 7 */
-		0x08,		/* values for codes of length 8 */
-		0x09,		/* values for codes of length 9 */
-		0x0a,		/* values for codes of length 10 */
-		0x0b,		/* values for codes of length 11 */
-		0x10,
-		0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
-		0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
-		0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
-		0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
-		0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
-		0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
-		0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
-		0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
-		0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
-		0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
-		0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
-		0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
-		0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
-		0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
-		0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
-		0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-		0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
-		0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
-		0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
-		0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
-		0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
-		0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
-		0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
-		0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
-		0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
-		0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
-		0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,
-		0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23,
-		0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a,
-		0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
-		0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35,
-		0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
-		0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55,
-		0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
-		0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
-		0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84,
-		0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
-		0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
-		0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
-		0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
-		0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
-		0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-		0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
-		0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5,
-		0xf6, 0xf7, 0xf8, 0xf9, 0xfa
-	};
-
-	/* write fixed Huffman tables */
-	adr = 0x1d4;
-	for (i = 0; i < sizeof(dht); ++i) {
-		zr36060_write_8(zr, adr++, dht[i]);
-	}
-}
-
-static void zr36060_set_jpg_APP(struct zoran *zr)
-{
-	unsigned adr;
-	int len, i;
-	u32 reg;
-
-
-	len = zr->params.APP_len;
-	if (len < 0)
-		len = 0;
-	if (len > 60)
-		len = 60;
-
-	i = zr->params.APPn;
-	if (i < 0)
-		i = 0;
-	if (i > 15)
-		i = 15;
-
-	reg = 0xffe0 + i;	/* APPn marker */
-	zr36060_write_16(zr, 0x380, reg);
-
-	reg = len + 2;		/* APPn len */
-	zr36060_write_16(zr, 0x382, reg);
-
-	/* write APPn data */
-	adr = 0x384;
-	for (i = 0; i < 60; i++) {
-		zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0));
-	}
-}
-
-static void zr36060_set_jpg_COM(struct zoran *zr)
-{
-	unsigned adr;
-	int len, i;
-	u32 reg;
-
-
-	len = zr->params.COM_len;
-	if (len < 0)
-		len = 0;
-	if (len > 60)
-		len = 60;
-
-	reg = 0xfffe;		/* COM marker */
-	zr36060_write_16(zr, 0x3c0, reg);
-
-	reg = len + 2;		/* COM len */
-	zr36060_write_16(zr, 0x3c2, reg);
-
-	/* write COM data */
-	adr = 0x3c4;
-	for (i = 0; i < 60; i++) {
-		zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0));
-	}
-}
-
-static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode)
-{
-	unsigned i;
-	u32 reg;
-
-	zr36060_reset(zr);
-	mdelay(10);
-
-	reg = (0 << 7)		/* Load=0 */
-	    |(1 << 0);		/* SynRst=1 */
-	zr36060_write_8(zr, 0x000, reg);
-
-	zr36060_set_jpg(zr, mode);
-	zr36060_set_video(zr, mode);
-	zr36060_set_jpg_SOF(zr);
-	zr36060_set_jpg_SOS(zr);
-	zr36060_set_jpg_DRI(zr);
-	zr36060_set_jpg_DQT(zr);
-	zr36060_set_jpg_DHT(zr);
-	zr36060_set_jpg_APP(zr);
-	zr36060_set_jpg_COM(zr);
-
-	reg = (1 << 7)		/* Load=1 */
-	    |(0 << 0);		/* SynRst=0 */
-	zr36060_write_8(zr, 0x000, reg);
-
-	/* wait for codec to unbusy */
-	for (i = 0; i < 1000; ++i) {
-		reg = zr36060_read_8(zr, 0x001);
-		if ((reg & (1 << 7)) == 0) {
-			DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i));
-			return;
-		}
-		udelay(1000);
-	}
-	printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg);
-}
-
-static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
-{
-	struct tvnorm *tvn;
-	u32 reg;
-	int i;
-
-	tvn = &tvnorms[zr->params.norm];
-
-	/* assert P_Reset */
-	btwrite(0, ZR36057_JPC);
-
-	/* re-initialize DMA ring stuff */
-	zr->jpg_que_head = 0;
-	zr->jpg_dma_head = 0;
-	zr->jpg_dma_tail = 0;
-	zr->jpg_que_tail = 0;
-	zr->jpg_seq_num = 0;
-	for (i = 0; i < BUZ_NUM_STAT_COM; ++i) {
-		zr->stat_com[i] = 1;	/* mark as unavailable to zr36057 */
-	}
-	for (i = 0; i < zr->jpg_nbufs; i++) {
-		zr->jpg_gbuf[i].state = BUZ_STATE_USER;	/* nothing going on */
-	}
-
-	/* MJPEG compression mode */
-	switch (mode) {
-
-	case BUZ_MODE_MOTION_COMPRESS:
-	default:
-		reg = ZR36057_JMC_MJPGCmpMode;
-		break;
-
-	case BUZ_MODE_MOTION_DECOMPRESS:
-		reg = ZR36057_JMC_MJPGExpMode;
-		reg |= ZR36057_JMC_SyncMstr;
-		/* RJ: The following is experimental - improves the output to screen */
-		if (zr->params.VFIFO_FB)
-			reg |= ZR36057_JMC_VFIFO_FB;
-		break;
-
-	case BUZ_MODE_STILL_COMPRESS:
-		reg = ZR36057_JMC_JPGCmpMode;
-		break;
-
-	case BUZ_MODE_STILL_DECOMPRESS:
-		reg = ZR36057_JMC_JPGExpMode;
-		break;
-
-	}
-	reg |= ZR36057_JMC_JPG;
-	if (zr->params.field_per_buff == 1)
-		reg |= ZR36057_JMC_Fld_per_buff;
-	btwrite(reg, ZR36057_JMC);
-
-	/* vertical */
-	btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
-	reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot);
-	btwrite(reg, ZR36057_VSP);
-	reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY)
-	    | (zr->params.img_height << ZR36057_FVAP_PAY);
-	btwrite(reg, ZR36057_FVAP);
-
-	/* horizontal */
-	btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
-	reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot);
-	btwrite(reg, ZR36057_HSP);
-	reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX)
-	    | (zr->params.img_width << ZR36057_FHAP_PAX);
-	btwrite(reg, ZR36057_FHAP);
-
-	/* field process parameters */
-	if (zr->params.odd_even)
-		reg = ZR36057_FPP_Odd_Even;
-	else
-		reg = 0;
-	btwrite(reg, ZR36057_FPP);
-
-	/* Set proper VCLK Polarity, else colors will be wrong during playback */
-	btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
-
-	/* code base address and FIFO threshold */
-	reg = virt_to_bus(zr->stat_com);
-	btwrite(reg, ZR36057_JCBA);
-	reg = 0x50;
-	btwrite(reg, ZR36057_JCFT);
-
-	/* JPEG codec guest ID */
-	reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg);
-	btwrite(reg, ZR36057_JCGI);
-
-	/* Code transfer guest ID */
-	reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg);
-	reg |= ZR36057_MCTCR_CFlush;
-	btwrite(reg, ZR36057_MCTCR);
-
-	/* deassert P_Reset */
-	btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
-}
-
-static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode)
-{
-	static int zero = 0;
-	static int one = 1;
-
-	switch (mode) {
-
-	case BUZ_MODE_MOTION_COMPRESS:
-		zr36060_set_cap(zr, mode);
-		zr36057_set_jpg(zr, mode);
-		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one);
-		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero);
-
-		/* deassert P_Reset, assert Code transfer enable */
-		btwrite(IRQ_MASK, ZR36057_ISR);
-		btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-		break;
-
-	case BUZ_MODE_MOTION_DECOMPRESS:
-		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero);
-		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one);
-		zr36060_set_cap(zr, mode);
-		zr36057_set_jpg(zr, mode);
-
-		/* deassert P_Reset, assert Code transfer enable */
-		btwrite(IRQ_MASK, ZR36057_ISR);
-		btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-		break;
-
-	case BUZ_MODE_IDLE:
-	default:
-		/* shut down processing */
-		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-		btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);
-		btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
-		btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
-		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
-		btwrite(0, ZR36057_ISR);
-		zr36060_reset(zr);
-		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one);
-		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero);
-		break;
-
-	}
-	zr->codec_mode = mode;
-}
-
-/*
- *   Queue a MJPEG buffer for capture/playback
- */
-
-static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode)
-{
-	unsigned long flags;
-	int res;
-
-	/* Check if buffers are allocated */
-
-	if (!zr->jpg_buffers_allocated) {
-		printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name);
-		return -ENOMEM;
-	}
-	/* Does the user want to stop streaming? */
-
-	if (frame < 0) {
-		if (zr->codec_mode == mode) {
-			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-			return 0;
-		} else {
-			printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name);
-			return -EINVAL;
-		}
-	}
-	/* No grabbing outside the buffer range! */
-
-	if (frame >= zr->jpg_nbufs) {
-		printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame);
-		return -EINVAL;
-	}
-	/* what is the codec mode right now? */
-
-	if (zr->codec_mode == BUZ_MODE_IDLE) {
-		/* Ok load up the zr36060 and go */
-		zr36057_enable_jpg(zr, mode);
-	} else if (zr->codec_mode != mode) {
-		/* wrong codec mode active - invalid */
-		printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name);
-		return -EINVAL;
-	}
-	spin_lock_irqsave(&zr->lock, flags);
-
-	/* make sure a grab isn't going on currently with this buffer */
-
-	switch (zr->jpg_gbuf[frame].state) {
-
-	default:
-	case BUZ_STATE_DMA:
-	case BUZ_STATE_PEND:
-	case BUZ_STATE_DONE:
-		res = -EBUSY;	/* what are you doing? */
-		break;
-
-	case BUZ_STATE_USER:
-		/* since there is at least one unused buffer there's room for at least one more pend[] entry */
-		zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame;
-		zr->jpg_gbuf[frame].state = BUZ_STATE_PEND;
-		zoran_feed_stat_com(zr);
-		res = 0;
-		break;
-
-	}
-
-	spin_unlock_irqrestore(&zr->lock, flags);
-
-	/* Start the zr36060 when the first frame is queued  */
-	if (zr->jpg_que_head == 1) {
-		btor(ZR36057_JMC_Go_en, ZR36057_JMC);
-		btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC);
-	}
-	return res;
-}
-
-/*
- *   Sync on a MJPEG buffer
- */
-
-static int jpg_sync(struct zoran *zr, struct zoran_sync *bs)
-{
-	unsigned long flags;
-	int frame;
-
-	if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS &&
-	    zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
-		return -EINVAL;
-	}
-	while (zr->jpg_que_tail == zr->jpg_dma_tail) {
-		interruptible_sleep_on(&zr->jpg_capq);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
-
-	spin_lock_irqsave(&zr->lock, flags);
-
-	frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
-
-	/* buffer should now be in BUZ_STATE_DONE */
-
-	if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE)
-		printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name);
-
-	*bs = zr->jpg_gbuf[frame].bs;
-	zr->jpg_gbuf[frame].state = BUZ_STATE_USER;
-
-	spin_unlock_irqrestore(&zr->lock, flags);
-
-	return 0;
-}
-
-/* when this is called the spinlock must be held */
-static void zoran_feed_stat_com(struct zoran *zr)
-{
-	/* move frames from pending queue to DMA */
-
-	int frame, i, max_stat_com;
-
-	max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
-
-	while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com
-	       && zr->jpg_dma_head != zr->jpg_que_head) {
-
-		frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
-		if (zr->params.TmpDcm == 1) {
-			/* fill 1 stat_com entry */
-			i = zr->jpg_dma_head & BUZ_MASK_STAT_COM;
-			zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
-		} else {
-			/* fill 2 stat_com entries */
-			i = (zr->jpg_dma_head & 1) * 2;
-			zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
-			zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus;
-		}
-		zr->jpg_gbuf[frame].state = BUZ_STATE_DMA;
-		zr->jpg_dma_head++;
-
-	}
-}
-
-/* when this is called the spinlock must be held */
-static void zoran_reap_stat_com(struct zoran *zr)
-{
-	/* move frames from DMA queue to done queue */
-
-	int i;
-	u32 stat_com;
-	unsigned int seq;
-	unsigned int dif;
-	int frame;
-	struct zoran_gbuffer *gbuf;
-
-	/* In motion decompress we don't have a hardware frame counter,
-	   we just count the interrupts here */
-
-	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
-		zr->jpg_seq_num++;
-
-	while (zr->jpg_dma_tail != zr->jpg_dma_head) {
-		if (zr->params.TmpDcm == 1)
-			i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM;
-		else
-			i = (zr->jpg_dma_tail & 1) * 2 + 1;
-
-		stat_com = zr->stat_com[i];
-
-		if ((stat_com & 1) == 0) {
-			return;
-		}
-		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
-		gbuf = &zr->jpg_gbuf[frame];
-		get_fast_time(&gbuf->bs.timestamp);
-
-		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-			gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
-
-			/* update sequence number with the help of the counter in stat_com */
-
-			seq = stat_com >> 24;
-			dif = (seq - zr->jpg_seq_num) & 0xff;
-			zr->jpg_seq_num += dif;
-		} else {
-			gbuf->bs.length = 0;
-		}
-		gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
-		gbuf->state = BUZ_STATE_DONE;
-
-		zr->jpg_dma_tail++;
-	}
-}
-
-static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	u32 stat, astat;
-	int count;
-	struct zoran *zr;
-	unsigned long flags;
-
-	zr = (struct zoran *) dev_id;
-	count = 0;
-
-	spin_lock_irqsave(&zr->lock, flags);
-	while (1) {
-		/* get/clear interrupt status bits */
-		stat = btread(ZR36057_ISR);
-		astat = stat & IRQ_MASK;
-		if (!astat) {
-			break;
-		}
-		btwrite(astat, ZR36057_ISR);
-		IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat));
-
-#if (IRQ_MASK & ZR36057_ISR_GIRQ0)
-		if (astat & ZR36057_ISR_GIRQ0) {
-
-			/* Interrupts may still happen when zr->v4l_memgrab_active is switched off.
-			   We simply ignore them */
-
-			if (zr->v4l_memgrab_active) {
-
-/* A lot more checks should be here ... */
-				if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0)
-					printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name);
-
-				if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
-					/* There is a grab on a frame going on, check if it has finished */
-
-					if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) {
-						/* it is finished, notify the user */
-
-						zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
-						zr->v4l_grab_frame = NO_GRAB_ACTIVE;
-						zr->v4l_grab_seq++;
-						zr->v4l_pend_tail++;
-					}
-				}
-				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
-					wake_up_interruptible(&zr->v4l_capq);
-
-				/* Check if there is another grab queued */
-
-				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE &&
-				    zr->v4l_pend_tail != zr->v4l_pend_head) {
-
-					int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
-					u32 reg;
-
-					zr->v4l_grab_frame = frame;
-
-					/* Set zr36057 video front end and enable video */
-
-					/* Buffer address */
-
-					reg = zr->v4l_gbuf[frame].fbuffer_bus;
-					btwrite(reg, ZR36057_VDTR);
-					if (zr->video_interlace)
-						reg += zr->gbpl;
-					btwrite(reg, ZR36057_VDBR);
-
-					/* video stride, status, and frame grab register */
-
-#ifdef XAWTV_HACK
-					reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0;
-#else
-					reg = 0;
-#endif
-					if (zr->video_interlace)
-						reg += zr->gbpl;
-					reg = (reg << ZR36057_VSSFGR_DispStride);
-					reg |= ZR36057_VSSFGR_VidOvf;
-					reg |= ZR36057_VSSFGR_SnapShot;
-					reg |= ZR36057_VSSFGR_FrameGrab;
-					btwrite(reg, ZR36057_VSSFGR);
-
-					btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
-				}
-			}
-		}
-#endif				/* (IRQ_MASK & ZR36057_ISR_GIRQ0) */
-
-#if (IRQ_MASK & ZR36057_ISR_GIRQ1)
-		if (astat & ZR36057_ISR_GIRQ1) {
-			unsigned csr = zr36060_read_8(zr, 0x001);
-			unsigned isr = zr36060_read_8(zr, 0x008);
-
-			IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n",
-				      zr->name, csr, isr));
-
-			btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR);
-			zoran_reap_stat_com(zr);
-			zoran_feed_stat_com(zr);
-		}
-#endif				/* (IRQ_MASK & ZR36057_ISR_GIRQ1) */
-
-#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
-		if (astat & ZR36057_ISR_CodRepIRQ) {
-			IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name));
-			btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
-		}
-#endif				/* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
-
-#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
-		if ((astat & ZR36057_ISR_JPEGRepIRQ) &&
-		    (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
-		     zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
-			zoran_reap_stat_com(zr);
-			zoran_feed_stat_com(zr);
-			wake_up_interruptible(&zr->jpg_capq);
-		}
-#endif				/* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
-
-		count++;
-		if (count > 10) {
-			printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count);
-			if (count > 20) {
-				btwrite(0, ZR36057_ICR);
-				printk(KERN_ERR  "%s: IRQ lockup, cleared int mask\n", zr->name);
-				break;
-			}
-		}
-	}
-	spin_unlock_irqrestore(&zr->lock, flags);
-}
-
-/* Check a zoran_params struct for correctness, insert default params */
-
-static int zoran_check_params(struct zoran *zr, struct zoran_params *params)
-{
-	int err = 0, err0 = 0;
-
-	/* insert constant params */
-
-	params->major_version = MAJOR_VERSION;
-	params->minor_version = MINOR_VERSION;
-
-	/* Check input and norm */
-
-	if (params->input != 0 && params->input != 1) {
-		err++;
-	}
-	if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) {
-		err++;
-	}
-	/* Check decimation, set default values for decimation = 1, 2, 4 */
-
-	switch (params->decimation) {
-	case 1:
-
-		params->HorDcm = 1;
-		params->VerDcm = 1;
-		params->TmpDcm = 1;
-		params->field_per_buff = 2;
-
-		params->img_x = 0;
-		params->img_y = 0;
-		params->img_width = 720;
-		params->img_height = tvnorms[params->norm].Ha / 2;
-		break;
-
-	case 2:
-
-		params->HorDcm = 2;
-		params->VerDcm = 1;
-		params->TmpDcm = 2;
-		params->field_per_buff = 1;
-
-		params->img_x = 8;
-		params->img_y = 0;
-		params->img_width = 704;
-		params->img_height = tvnorms[params->norm].Ha / 2;
-		break;
-
-	case 4:
-
-		params->HorDcm = 4;
-		params->VerDcm = 2;
-		params->TmpDcm = 2;
-		params->field_per_buff = 1;
-
-		params->img_x = 8;
-		params->img_y = 0;
-		params->img_width = 704;
-		params->img_height = tvnorms[params->norm].Ha / 2;
-		break;
-
-	case 0:
-
-		/* We have to check the data the user has set */
-
-		if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4)
-			err0++;
-		if (params->VerDcm != 1 && params->VerDcm != 2)
-			err0++;
-		if (params->TmpDcm != 1 && params->TmpDcm != 2)
-			err0++;
-		if (params->field_per_buff != 1 && params->field_per_buff != 2)
-			err0++;
-
-		if (params->img_x < 0)
-			err0++;
-		if (params->img_y < 0)
-			err0++;
-		if (params->img_width < 0)
-			err0++;
-		if (params->img_height < 0)
-			err0++;
-		if (params->img_x + params->img_width > 720)
-			err0++;
-		if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2)
-			err0++;
-		if (params->img_width % (16 * params->HorDcm) != 0)
-			err0++;
-		if (params->img_height % (8 * params->VerDcm) != 0)
-			err0++;
-
-		if (err0) {
-			err++;
-		}
-		break;
-
-	default:
-		err++;
-		break;
-	}
-
-	if (params->quality > 100)
-		params->quality = 100;
-	if (params->quality < 5)
-		params->quality = 5;
-
-	if (params->APPn < 0)
-		params->APPn = 0;
-	if (params->APPn > 15)
-		params->APPn = 15;
-	if (params->APP_len < 0)
-		params->APP_len = 0;
-	if (params->APP_len > 60)
-		params->APP_len = 60;
-	if (params->COM_len < 0)
-		params->COM_len = 0;
-	if (params->COM_len > 60)
-		params->COM_len = 60;
-
-	if (err)
-		return -EINVAL;
-
-	return 0;
-
-}
-static void zoran_open_init_params(struct zoran *zr)
-{
-	int i;
-
-	/* Per default, map the V4L Buffers */
-
-	zr->map_mjpeg_buffers = 0;
-
-	/* User must explicitly set a window */
-
-	zr->window_set = 0;
-
-	zr->window.x = 0;
-	zr->window.y = 0;
-	zr->window.width = 0;
-	zr->window.height = 0;
-	zr->window.chromakey = 0;
-	zr->window.flags = 0;
-	zr->window.clips = NULL;
-	zr->window.clipcount = 0;
-
-	zr->video_interlace = 0;
-
-	zr->v4l_memgrab_active = 0;
-	zr->v4l_overlay_active = 0;
-
-	zr->v4l_grab_frame = NO_GRAB_ACTIVE;
-	zr->v4l_grab_seq = 0;
-
-	zr->gwidth = 0;
-	zr->gheight = 0;
-	zr->gformat = 0;
-	zr->gbpl = 0;
-
-	/* DMA ring stuff for V4L */
-
-	zr->v4l_pend_tail = 0;
-	zr->v4l_pend_head = 0;
-	for (i = 0; i < v4l_nbufs; i++) {
-		zr->v4l_gbuf[i].state = BUZ_STATE_USER;	/* nothing going on */
-	}
-
-	/* Set necessary params and call zoran_check_params to set the defaults */
-
-	zr->params.decimation = 1;
-
-	zr->params.quality = 50;	/* default compression factor 8 */
-	zr->params.odd_even = 1;
-
-	zr->params.APPn = 0;
-	zr->params.APP_len = 0;	/* No APPn marker */
-	for (i = 0; i < 60; i++)
-		zr->params.APP_data[i] = 0;
-
-	zr->params.COM_len = 0;	/* No COM marker */
-	for (i = 0; i < 60; i++)
-		zr->params.COM_data[i] = 0;
-
-	zr->params.VFIFO_FB = 0;
-
-	memset(zr->params.reserved, 0, sizeof(zr->params.reserved));
-
-	zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT;
-
-	i = zoran_check_params(zr, &zr->params);
-	if (i)
-		printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name);
-}
-
-/*
- *   Open a buz card. Right now the flags stuff is just playing
- */
-
-static int zoran_open(struct video_device *dev, int flags)
-{
-	struct zoran *zr = (struct zoran *) dev;
-
-	DEBUG(printk(KERN_INFO ": zoran_open\n"));
-
-	switch (flags) {
-
-	case 0:
-		if (zr->user)
-			return -EBUSY;
-		zr->user++;
-
-		if (v4l_fbuffer_alloc(zr) < 0) {
-			zr->user--;
-			return -ENOMEM;
-		}
-		/* default setup */
-
-		zoran_open_init_params(zr);
-
-		zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-
-		btwrite(IRQ_MASK, ZR36057_ISR);		// Clears interrupts
-
-		btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
-
-		break;
-
-	default:
-		return -EBUSY;
-
-	}
-	return 0;
-}
-
-static void zoran_close(struct video_device *dev)
-{
-	struct zoran *zr = (struct zoran *) dev;
-
-	DEBUG(printk(KERN_INFO ": zoran_close\n"));
-	
-	/* disable interrupts */
-	btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
-
-	/* wake up sleeping beauties */
-	wake_up_interruptible(&zr->v4l_capq);
-	wake_up_interruptible(&zr->jpg_capq);
-
-	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
-	zr36057_set_memgrab(zr, 0);
-	if (zr->v4l_overlay_active)
-		zr36057_overlay(zr, 0);
-
-	zr->user--;
-
-	v4l_fbuffer_free(zr);
-	jpg_fbuffer_free(zr);
-	zr->jpg_nbufs = 0;
-
-	DEBUG(printk(KERN_INFO ": zoran_close done\n"));
-}
-
-
-static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock)
-{
-	return -EINVAL;
-}
-
-static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock)
-{
-	return -EINVAL;
-}
-
-/*
- *   ioctl routine
- */
-
-
-static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
-	struct zoran *zr = (struct zoran *) dev;
-
-	switch (cmd) {
-
-	case VIDIOCGCAP:
-		{
-			struct video_capability b;
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n"));
-			strncpy(b.name, zr->video_dev.name, sizeof(b.name));
-			b.type = VID_TYPE_CAPTURE |
-			    VID_TYPE_OVERLAY |
-			    VID_TYPE_CLIPPING |
-			    VID_TYPE_FRAMERAM |
-			    VID_TYPE_SCALES;
-			/* theoretically we could also flag VID_TYPE_SUBCAPTURE
-			   but this is not even implemented in the BTTV driver */
-
-			b.channels = 2;		/* composite, svhs */
-			b.audios = 0;
-			b.maxwidth = BUZ_MAX_WIDTH;
-			b.maxheight = BUZ_MAX_HEIGHT;
-			b.minwidth = BUZ_MIN_WIDTH;
-			b.minheight = BUZ_MIN_HEIGHT;
-			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;
-			}
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel));
-			switch (v.channel) {
-			case 0:
-				strcpy(v.name, "Composite");
-				break;
-			case 1:
-				strcpy(v.name, "SVHS");
-				break;
-			default:
-				return -EINVAL;
-			}
-			v.tuners = 0;
-			v.flags = 0;
-			v.type = VIDEO_TYPE_CAMERA;
-			v.norm = zr->params.norm;
-			if (copy_to_user(arg, &v, sizeof(v))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-		/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
-
-		 * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
-		 *                                 ^^^^^^^
-		 * The famos BTTV driver has it implemented with a struct video_channel argument
-		 * and we follow it for compatibility reasons
-		 *
-		 * BTW: this is the only way the user can set the norm!
-		 */
-
-	case VIDIOCSCHAN:
-		{
-			struct video_channel v;
-			int input;
-			int on, res;
-
-			if (copy_from_user(&v, arg, sizeof(v))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm));
-			switch (v.channel) {
-			case 0:
-				input = 3;
-				break;
-			case 1:
-				input = 7;
-				break;
-			default:
-				return -EINVAL;
-			}
-
-			if (v.norm != VIDEO_MODE_PAL
-			    && v.norm != VIDEO_MODE_NTSC) {
-				return -EINVAL;
-			}
-			zr->params.norm = v.norm;
-			zr->params.input = v.channel;
-
-			/* We switch overlay off and on since a change in the norm
-			   needs different VFE settings */
-
-			on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
-			if (on)
-				zr36057_overlay(zr, 0);
-
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
-
-			if (on)
-				zr36057_overlay(zr, 1);
-
-			/* Make sure the changes come into effect */
-			res = wait_grab_pending(zr);
-			if (res)
-				return res;
-
-			return 0;
-		}
-
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-			return -EINVAL;
-
-	case VIDIOCGPICT:
-		{
-			struct video_picture p = zr->picture;
-
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n"));
-			p.depth = zr->buffer.depth;
-			switch (zr->buffer.depth) {
-			case 15:
-				p.palette = VIDEO_PALETTE_RGB555;
-				break;
-
-			case 16:
-				p.palette = VIDEO_PALETTE_RGB565;
-				break;
-
-			case 24:
-				p.palette = VIDEO_PALETTE_RGB24;
-				break;
-
-			case 32:
-				p.palette = VIDEO_PALETTE_RGB32;
-				break;
-			}
-
-			if (copy_to_user(arg, &p, sizeof(p))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	case VIDIOCSPICT:
-		{
-			struct video_picture p;
-
-			if (copy_from_user(&p, arg, sizeof(p))) {
-				return -EFAULT;
-			}
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n",
-					   p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette));
-			/* The depth and palette values have no meaning to us,
-			   should we return  -EINVAL if they don't fit ? */
-			zr->picture = p;
-			return 0;
-		}
-
-	case VIDIOCCAPTURE:
-		{
-			int v, res;
-
-			if (copy_from_user(&v, arg, sizeof(v))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v));
-			/* If there is nothing to do, return immediatly */
-
-			if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active))
-				return 0;
-
-			if (v == 0) {
-				zr->v4l_overlay_active = 0;
-				if (!zr->v4l_memgrab_active)
-					zr36057_overlay(zr, 0);
-				/* When a grab is running, the video simply won't be switched on any more */
-			} else {
-				if (!zr->buffer_set || !zr->window_set) {
-					return -EINVAL;
-				}
-				zr->v4l_overlay_active = 1;
-				if (!zr->v4l_memgrab_active)
-					zr36057_overlay(zr, 1);
-				/* When a grab is running, the video will be switched on when grab is finished */
-			}
-			/* Make sure the changes come into effect */
-			res = wait_grab_pending(zr);
-			if (res)
-				return res;
-			return 0;
-		}
-
-	case VIDIOCGWIN:
-		{
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n"));
-			if (copy_to_user(arg, &zr->window, sizeof(zr->window))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	case VIDIOCSWIN:
-		{
-			struct video_clip *vcp;
-			struct video_window vw;
-			int on, end, res;
-
-			if (copy_from_user(&vw, arg, sizeof(vw))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount));
-			if (!zr->buffer_set) {
-				return -EINVAL;
-			}
-			/*
-			 * The video front end needs 4-byte alinged line sizes, we correct that
-			 * silently here if necessary
-			 */
-
-			if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
-				end = (vw.x + vw.width) & ~1;	/* round down */
-				vw.x = (vw.x + 1) & ~1;		/* round up */
-				vw.width = end - vw.x;
-			}
-			if (zr->buffer.depth == 24) {
-				end = (vw.x + vw.width) & ~3;	/* round down */
-				vw.x = (vw.x + 3) & ~3;		/* round up */
-				vw.width = end - vw.x;
-			}
-#if 0
-			// At least xawtv seems to care about the following - just leave it away
-			/*
-			 * Also corrected silently (as long as window fits at all):
-			 * video not fitting the screen
-			 */
-#if 0
-			if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width ||
-			    vw.y + vw.height > zr->buffer.height) {
-				printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n",
-				       vw.width, vw.height, vw.x, vw.y);
-				return -EINVAL;
-			}
-#else
-			if (vw.x < 0)
-				vw.x = 0;
-			if (vw.y < 0)
-				vw.y = 0;
-			if (vw.x + vw.width > zr->buffer.width)
-				vw.width = zr->buffer.width - vw.x;
-			if (vw.y + vw.height > zr->buffer.height)
-				vw.height = zr->buffer.height - vw.y;
-#endif
-#endif
-
-			/* Check for valid parameters */
-			if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT ||
-			    vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) {
-				return -EINVAL;
-			}
-#ifdef XAWTV_HACK
-			if (vw.width > 720)
-				vw.width = 720;
-#endif
-
-			zr->window.x = vw.x;
-			zr->window.y = vw.y;
-			zr->window.width = vw.width;
-			zr->window.height = vw.height;
-			zr->window.chromakey = 0;
-			zr->window.flags = 0;	// RJ: Is this intended for interlace on/off ?
-
-			zr->window.clips = NULL;
-			zr->window.clipcount = vw.clipcount;
-
-			/*
-			 * If an overlay is running, we have to switch it off
-			 * and switch it on again in order to get the new settings in effect.
-			 *
-			 * We also want to avoid that the overlay mask is written
-			 * when an overlay is running.
-			 */
-
-			on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
-			if (on)
-				zr36057_overlay(zr, 0);
-
-			/*
-			 *   Write the overlay mask if clips are wanted.
-			 */
-			if (vw.clipcount) {
-				vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4));
-				if (vcp == NULL) {
-					return -ENOMEM;
-				}
-				if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) {
-					vfree(vcp);
-					return -EFAULT;
-				}
-				write_overlay_mask(zr, vcp, vw.clipcount);
-				vfree(vcp);
-			}
-			if (on)
-				zr36057_overlay(zr, 1);
-			zr->window_set = 1;
-
-			/* Make sure the changes come into effect */
-			res = wait_grab_pending(zr);
-			if (res)
-				return res;
-
-			return 0;
-		}
-
-	case VIDIOCGFBUF:
-		{
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n"));
-			if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	case VIDIOCSFBUF:
-		{
-			struct video_buffer v;
-
-			if (!capable(CAP_SYS_ADMIN)
-			|| !capable(CAP_SYS_RAWIO))
-				return -EPERM;
-
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline));
-			if (zr->v4l_overlay_active) {
-				/* Has the user gotten crazy ... ? */
-				return -EINVAL;
-			}
-			if (v.depth != 15
-			    && v.depth != 16
-			    && v.depth != 24
-			    && v.depth != 32) {
-				return -EINVAL;
-			}
-			if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) {
-				return -EINVAL;
-			}
-			if (v.bytesperline & 3) {
-				return -EINVAL;
-			}
-			if (v.base) {
-				zr->buffer.base = (void *) ((unsigned long) v.base & ~3);
-			}
-			zr->buffer.height = v.height;
-			zr->buffer.width = v.width;
-			zr->buffer.depth = v.depth;
-			zr->buffer.bytesperline = v.bytesperline;
-
-			if (zr->buffer.base)
-				zr->buffer_set = 1;
-			zr->window_set = 0;	/* The user should set new window parameters */
-			return 0;
-		}
-
-		/* RJ: what is VIDIOCKEY intended to do ??? */
-
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return -EINVAL;
-		
-	case VIDIOCSYNC:
-		{
-			int v;
-
-			if (copy_from_user(&v, arg, sizeof(v))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v));
-			return v4l_sync(zr, v);
-		}
-
-	case VIDIOCMCAPTURE:
-		{
-			struct video_mmap vm;
-
-			if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n",
-			       vm.frame, vm.height, vm.width, vm.format));
-			return v4l_grab(zr, &vm);
-		}
-
-	case VIDIOCGMBUF:
-		{
-			struct video_mbuf vm;
-			int i;
-
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n"));
-		
-			vm.size = v4l_nbufs * v4l_bufsize;
-			vm.frames = v4l_nbufs;
-			for (i = 0; i < v4l_nbufs; i++) {
-				vm.offsets[i] = i * v4l_bufsize;
-			}
-
-			/* The next mmap will map the V4L buffers */
-			zr->map_mjpeg_buffers = 0;
-
-			if (copy_to_user(arg, &vm, sizeof(vm))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	case VIDIOCGUNIT:
-		{
-			struct video_unit vu;
-
-			IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n"));
-			vu.video = zr->video_dev.minor;
-			vu.vbi = VIDEO_NO_UNIT;
-			vu.radio = VIDEO_NO_UNIT;
-			vu.audio = VIDEO_NO_UNIT;
-			vu.teletext = VIDEO_NO_UNIT;
-			if (copy_to_user(arg, &vu, sizeof(vu)))
-				return -EFAULT;
-			return 0;
-		}
-
-		/*
-		 * RJ: In principal we could support subcaptures for V4L grabbing.
-		 *     Not even the famous BTTV driver has them, however.
-		 *     If there should be a strong demand, one could consider
-		 *     to implement them.
-		 */
-	case VIDIOCGCAPTURE:
-	case VIDIOCSCAPTURE:
-			return -EINVAL;
-
-	case BUZIOC_G_PARAMS:
-		{
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n"));
-			if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) 
-				return -EFAULT;
-			return 0;
-		}
-
-	case BUZIOC_S_PARAMS:
-		{
-			struct zoran_params bp;
-			int input, on;
-
-			if (zr->codec_mode != BUZ_MODE_IDLE) {
-				return -EINVAL;
-			}
-			if (copy_from_user(&bp, arg, sizeof(bp))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n"));
-			
-			/* Check the params first before overwriting our internal values */
-
-			if (zoran_check_params(zr, &bp))
-				return -EINVAL;
-
-			zr->params = bp;
-
-			/* Make changes of input and norm go into effect immediatly */
-
-			/* We switch overlay off and on since a change in the norm
-			   needs different VFE settings */
-
-			on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
-			if (on)
-				zr36057_overlay(zr, 0);
-
-			input = zr->params.input == 0 ? 3 : 7;
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
-
-			if (on)
-				zr36057_overlay(zr, 1);
-
-			if (copy_to_user(arg, &bp, sizeof(bp))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	case BUZIOC_REQBUFS:
-		{
-			struct zoran_requestbuffers br;
-
-			if (zr->jpg_buffers_allocated) {
-				return -EINVAL;
-			}
-			if (copy_from_user(&br, arg, sizeof(br))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n",
-					   br.count, br.size));
-			/* Enforce reasonable lower and upper limits */
-			if (br.count < 4)
-				br.count = 4;	/* Could be choosen smaller */
-			if (br.count > BUZ_MAX_FRAME)
-				br.count = BUZ_MAX_FRAME;
-			br.size = PAGE_ALIGN(br.size);
-			if (br.size < 8192)
-				br.size = 8192;		/* Arbitrary */
-			/* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
-			if (br.size > (512 * 1024))
-				br.size = (512 * 1024);		/* 512 K should be enough */
-			if (zr->need_contiguous && br.size > KMALLOC_MAXSIZE)
-				br.size = KMALLOC_MAXSIZE;
-
-			zr->jpg_nbufs = br.count;
-			zr->jpg_bufsize = br.size;
-
-			if (jpg_fbuffer_alloc(zr))
-				return -ENOMEM;
-
-			/* The next mmap will map the MJPEG buffers */
-			zr->map_mjpeg_buffers = 1;
-
-			if (copy_to_user(arg, &br, sizeof(br))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	case BUZIOC_QBUF_CAPT:
-		{
-			int nb;
-
-			if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb));
-			return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS);
-		}
-
-	case BUZIOC_QBUF_PLAY:
-		{
-			int nb;
-
-			if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb));
-			return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS);
-		}
-
-	case BUZIOC_SYNC:
-		{
-			struct zoran_sync bs;
-			int res;
-
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n"));
-			res = jpg_sync(zr, &bs);
-			if (copy_to_user(arg, &bs, sizeof(bs))) {
-				return -EFAULT;
-			}
-			return res;
-		}
-
-	case BUZIOC_G_STATUS:
-		{
-			struct zoran_status bs;
-			int norm, input, status;
-
-			if (zr->codec_mode != BUZ_MODE_IDLE) {
-				return -EINVAL;
-			}
-			if (copy_from_user(&bs, arg, sizeof(bs))) {
-				return -EFAULT;
-			}
-			IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n"));
-			switch (bs.input) {
-			case 0:
-				input = 3;
-				break;
-			case 1:
-				input = 7;
-				break;
-			default:
-				return -EINVAL;
-			}
-
-			/* Set video norm to VIDEO_MODE_AUTO */
-
-			norm = VIDEO_MODE_AUTO;
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
-
-			/* sleep 1 second */
-
-			schedule_timeout(HZ);
-			
-			/* Get status of video decoder */
-
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status);
-			bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0;
-			bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
-			bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0;
-
-			/* restore previous input and norm */
-			input = zr->params.input == 0 ? 3 : 7;
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-
-			if (copy_to_user(arg, &bs, sizeof(bs))) {
-				return -EFAULT;
-			}
-			return 0;
-		}
-
-	default:
-		    return -ENOIOCTLCMD;
-
-	}
-	return 0;
-}
-
-
-/*
- *   This maps the buffers to user space.
- *
- *   Depending on the state of zr->map_mjpeg_buffers
- *   the V4L or the MJPEG buffers are mapped
- *
- */
-
-static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size)
-{
-	struct zoran *zr = (struct zoran *) dev;
-	unsigned long start = (unsigned long) adr;
-	unsigned long page, pos, todo, fraglen;
-	int i, j;
-
-	if (zr->map_mjpeg_buffers) {
-		/* Map the MJPEG buffers */
-
-		if (!zr->jpg_buffers_allocated) {
-			return -ENOMEM;
-		}
-		if (size > zr->jpg_nbufs * zr->jpg_bufsize) {
-			return -EINVAL;
-		}
-
-		for (i = 0; i < zr->jpg_nbufs; i++) {
-			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
-				fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1;
-				todo = size;
-				if (todo > fraglen)
-					todo = fraglen;
-				pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j];
-				page = virt_to_phys(bus_to_virt(pos));	/* should just be pos on i386 */
-				if (remap_page_range(start, page, todo, PAGE_SHARED)) {
-					printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name);
-					return -EAGAIN;
-				}
-				size -= todo;
-				start += todo;
-				if (size == 0)
-					break;
-				if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1)
-					break;	/* was last fragment */
-			}
-			if (size == 0)
-				break;
-		}
-	} else {
-		/* Map the V4L buffers */
-
-		if (size > v4l_nbufs * v4l_bufsize) {
-			return -EINVAL;
-		}
-
-		for (i = 0; i < v4l_nbufs; i++) {
-			todo = size;
-			if (todo > v4l_bufsize)
-				todo = v4l_bufsize;
-			page = zr->v4l_gbuf[i].fbuffer_phys;
-			DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start));
-			if (remap_page_range(start, page, todo, PAGE_SHARED)) {
-				printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name);
-				return -EAGAIN;
-			}
-			size -= todo;
-			start += todo;
-			if (size == 0)
-				break;
-		}
-	}
-	return 0;
-}
-
-static struct video_device zoran_template =
-{
-	owner:		THIS_MODULE,
-	name:		BUZ_NAME,
-	type:		VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
-			VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
-	hardware:	VID_HARDWARE_ZR36067,
-	open:		zoran_open,
-	close:		zoran_close,
-	read:		zoran_read,
-	write:		zoran_write,
-	ioctl:		zoran_ioctl,
-	mmap:		zoran_mmap,
-};
-
-static int zr36057_init(int i)
-{
-	struct zoran *zr = &zoran[i];
-	unsigned long mem;
-	unsigned mem_needed;
-	int j;
-	int rev;
-
-	/* reset zr36057 */
-	btwrite(0, ZR36057_SPGPPCR);
-	mdelay(10);
-
-	/* default setup of all parameters which will persist beetween opens */
-
-	zr->user = 0;
-	
-	init_waitqueue_head(&zr->v4l_capq);
-	init_waitqueue_head(&zr->jpg_capq);
-
-	zr->map_mjpeg_buffers = 0;	/* Map V4L buffers by default */
-
-	zr->jpg_nbufs = 0;
-	zr->jpg_bufsize = 0;
-	zr->jpg_buffers_allocated = 0;
-
-	zr->buffer_set = 0;	/* Flag if frame buffer has been set */
-	zr->buffer.base = (void *) vidmem;
-	zr->buffer.width = 0;
-	zr->buffer.height = 0;
-	zr->buffer.depth = 0;
-	zr->buffer.bytesperline = 0;
-
-	zr->params.norm = default_norm ? 1 : 0;	/* Avoid nonsense settings from user */
-	zr->params.input = default_input ? 1 : 0;	/* Avoid nonsense settings from user */
-	zr->video_interlace = 0;
-
-	/* Should the following be reset at every open ? */
-
-	zr->picture.colour = 32768;
-	zr->picture.brightness = 32768;
-	zr->picture.hue = 32768;
-	zr->picture.contrast = 32768;
-	zr->picture.whiteness = 0;
-	zr->picture.depth = 0;
-	zr->picture.palette = 0;
-
-	for (j = 0; j < VIDEO_MAX_FRAME; j++) {
-		zr->v4l_gbuf[i].fbuffer = 0;
-		zr->v4l_gbuf[i].fbuffer_phys = 0;
-		zr->v4l_gbuf[i].fbuffer_bus = 0;
-	}
-
-	zr->stat_com = 0;
-
-	/* default setup (will be repeated at every open) */
-
-	zoran_open_init_params(zr);
-
-	/* allocate memory *before* doing anything to the hardware in case allocation fails */
-
-	/* STAT_COM table and overlay mask */
-
-	mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4;
-	mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
-	if (!mem) {
-		return -ENOMEM;
-	}
-	memset((void *) mem, 0, mem_needed);
-
-	zr->stat_com = (u32 *) mem;
-	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-		zr->stat_com[j] = 1;	/* mark as unavailable to zr36057 */
-	}
-	zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4);
-
-	/* Initialize zr->jpg_gbuf */
-
-	for (j = 0; j < BUZ_MAX_FRAME; j++) {
-		zr->jpg_gbuf[j].frag_tab = 0;
-		zr->jpg_gbuf[j].frag_tab_bus = 0;
-		zr->jpg_gbuf[j].state = BUZ_STATE_USER;
-		zr->jpg_gbuf[j].bs.frame = j;
-	}
-
-	/* take zr36057 out of reset now */
-	btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
-	mdelay(10);
-
-	/* stop all DMA processes */
-	btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
-	btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
-	/* assert P_Reset */
-	btwrite(0, ZR36057_JPC);
-
-	switch(zr->board)
-	{
-		case BOARD_BUZ:
-	
-			/* set up GPIO direction */
-			btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
-
-			/* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */
-			btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1);
-			mdelay(10);
-
-			/* reset video decoder */
-
-			GPIO(zr, 0, 0);
-			mdelay(10);
-			GPIO(zr, 0, 1);
-			mdelay(10);
-
-			/* reset JPEG codec */
-			zr36060_sleep(zr, 0);
-			mdelay(10);
-			zr36060_reset(zr);
-			mdelay(10);
-	
-			/* display codec revision */
-			if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
-				printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
-			       zr->name, zr36060_read_8(zr, 0x023));
-			} else {
-				printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev);
-				kfree((void *) zr->stat_com);
-				return -1;
-			}
-			break;
-			
-		case BOARD_LML33:
-//			btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR);
-//			udelay(100);
-//			btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR);
-//			udelay(1000);
-
-			/*
-			 *	Set up the GPIO direction
-			 */
-			btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR);
-			/* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */
-			btwrite(0xFF00F888, ZR36057_GPPGCR1);
-			mdelay(10);
-			GPIO(zr, 5, 0);		/* Analog video bypass */
-			udelay(3000);
-			GPIO(zr, 0, 0); 	/* Reset 819 */
-			udelay(3000);
-			GPIO(zr, 0, 1);		/* 819 back */
-			udelay(3000);
-			/* reset JPEG codec */
-			zr36060_sleep(zr, 0);
-			udelay(3000);
-			zr36060_reset(zr);
-			udelay(3000);
-
-			/* display codec revision */
-			if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
-				printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
-			       zr->name, zr36060_read_8(zr, 0x023));
-			} else {
-				printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev);
-				kfree((void *) zr->stat_com);
-				return -1;
-			}
-			break;
-	}
-	/* i2c */
-	memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus));
-	sprintf(zr->i2c.name, "zoran%u", zr->id);
-	zr->i2c.data = zr;
-	if (i2c_register_bus(&zr->i2c) < 0) {
-		kfree((void *) zr->stat_com);
-		return -1;
-	}
-	/*
-	 *   Now add the template and register the device unit.
-	 */
-	memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
-	sprintf(zr->video_dev.name, "zoran%u", zr->id);
-	if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) {
-		i2c_unregister_bus(&zr->i2c);
-		kfree((void *) zr->stat_com);
-		return -1;
-	}
-	/* toggle JPEG codec sleep to sync PLL */
-	zr36060_sleep(zr, 1);
-	mdelay(10);
-	zr36060_sleep(zr, 0);
-	mdelay(10);
-
-	/* Enable bus-mastering */
-	pci_set_master(zr->pci_dev);
-
-	j = zr->params.input == 0 ? 3 : 7;
-	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j);
-	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
-
-	/* set individual interrupt enables (without GIRQ0)
-	   but don't global enable until zoran_open() */
-
-	btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR);
-
-	if(request_irq(zr->pci_dev->irq, zoran_irq,
-	       SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0)
-	{
-		printk(KERN_ERR "%s: Can't assign irq.\n", zr->name);
-		video_unregister_device(&zr->video_dev);
-		i2c_unregister_bus(&zr->i2c);
-		kfree((void *) zr->stat_com);
-		return -1;
-	}
-	zr->initialized = 1;
-	return 0;
-}
-
-
-
-static void release_zoran(void)
-{
-	u8 command;
-	int i;
-	struct zoran *zr;
-
-	for (i = 0; i < zoran_num; i++) {
-		zr = &zoran[i];
-
-		if (!zr->initialized)
-			continue;
-
-		/* unregister i2c_bus */
-		i2c_unregister_bus((&zr->i2c));
-
-		/* disable PCI bus-mastering */
-		pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command);
-		command &= ~PCI_COMMAND_MASTER;
-		pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command);
-
-		/* put chip into reset */
-		btwrite(0, ZR36057_SPGPPCR);
-
-		free_irq(zr->pci_dev->irq, zr);
-
-		/* unmap and free memory */
-
-		kfree((void *) zr->stat_com);
-
-		iounmap(zr->zr36057_mem);
-
-		video_unregister_device(&zr->video_dev);
-	}
-}
-
-/*
- *   Scan for a Buz card (actually for the PCI controller ZR36057),
- *   request the irq and map the io memory
- */
-
-static int find_zr36057(void)
-{
-	unsigned char latency;
-	struct zoran *zr;
-	struct pci_dev *dev = NULL;
-
-	zoran_num = 0;
-
-	while (zoran_num < BUZ_MAX
-	       && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
-		zr = &zoran[zoran_num];
-		zr->pci_dev = dev;
-		zr->zr36057_mem = NULL;
-		zr->id = zoran_num;
-		sprintf(zr->name, "zoran%u", zr->id);
-
-		spin_lock_init(&zr->lock);
-
-		if (pci_enable_device(dev))
-			continue;
-
-		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
-		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
-		if (zr->revision < 2) {
-			printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
-			       zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
-		} else {
-			unsigned short ss_vendor_id, ss_id;
-
-			ss_vendor_id = zr->pci_dev->subsystem_vendor;
-			ss_id = zr->pci_dev->subsystem_device;
-			printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
-			       zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr);
-			printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n",
-			       zr->name, ss_vendor_id, ss_id);
-			if(ss_vendor_id==0xFF10 && ss_id == 0xDE41)
-			{
-				zr->board = BOARD_LML33;
-				printk(KERN_INFO "%s: LML33 detected.\n", zr->name);
-			}
-		}
-
-		zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000);
-		if (!zr->zr36057_mem) {
-			printk(KERN_ERR "%s: ioremap failed\n", zr->name);
-			break;
-		}
-
-		/* set PCI latency timer */
-		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
-		if (latency != 48) {
-			printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency);
-			latency = 48;
-			pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency);
-		}
-		zoran_num++;
-	}
-	if (zoran_num == 0)
-		printk(KERN_INFO "zoran: no cards found.\n");
-
-	return zoran_num;
-}
-
-static void handle_chipset(void)
-{
-	if(pci_pci_problems&PCIPCI_FAIL)
-	{
-		printk(KERN_WARNING "buz: This configuration is known to have PCI to PCI DMA problems\n");
-		printk(KERN_WARNING "buz: You may not be able to use overlay mode.\n");
-	}
-			
-
-	if(pci_pci_problems&PCIPCI_TRITON)
-	{
-		printk("buz: Enabling Triton support.\n");
-		triton = 1;
-	}
-	
-	if(pci_pci_problems&PCIPCI_NATOMA)
-	{
-		printk("buz: Enabling Natoma workaround.\n");
-		natoma = 1;
-	}
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int init_zoran_cards(struct video_init *unused)
-#endif
-{
-	int i;
-
-
-	printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n");
-
-	/* Look for Buz cards */
-
-	if (find_zr36057() <= 0) {
-		return -EIO;
-	}
-	printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num);
-
-	if (zoran_num == 0)
-		return -ENXIO;
-
-	
-	/* check the parameters we have been given, adjust if necessary */
-
-	if (v4l_nbufs < 0)
-		v4l_nbufs = 0;
-	if (v4l_nbufs > VIDEO_MAX_FRAME)
-		v4l_nbufs = VIDEO_MAX_FRAME;
-	/* The user specfies the in KB, we want them in byte (and page aligned) */
-	v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
-	if (v4l_bufsize < 32768)
-		v4l_bufsize = 32768;
-	/* 2 MB is arbitrary but sufficient for the maximum possible images */
-	if (v4l_bufsize > 2048 * 1024)
-		v4l_bufsize = 2048 * 1024;
-
-	printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10);
-
-	/* Use parameter for vidmem or try to find a video card */
-
-	if (vidmem) {
-		printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem);
-	}
-
-	/* check if we have a Triton or Natome chipset */
-
-	handle_chipset();
-
-	/* take care of Natoma chipset and a revision 1 zr36057 */
-
-	for (i = 0; i < zoran_num; i++) {
-		if (natoma && zoran[i].revision <= 1) {
-			zoran[i].need_contiguous = 1;
-			printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name);
-		} else {
-			zoran[i].need_contiguous = 0;
-		}
-	}
-
-	/* initialize the Buzs */
-
-	/* We have to know which ones must be released if an error occurs */
-	for (i = 0; i < zoran_num; i++)
-		zoran[i].initialized = 0;
-
-	for (i = 0; i < zoran_num; i++) {
-		if (zr36057_init(i) < 0) {
-			release_zoran();
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
-
-
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-	release_zoran();
-}
-
-#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/buz.h linux/drivers/media/video/buz.h
--- v2.4.6/linux/drivers/media/video/buz.h	Mon Dec 11 13:15:49 2000
+++ linux/drivers/media/video/buz.h	Wed Dec 31 16:00:00 1969
@@ -1,319 +0,0 @@
-/* 
-   buz - Iomega Buz driver
-
-   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
-
-   based on
-
-   buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
-
-   and
-
-   bttv - Bt848 frame grabber driver
-   Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.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.
- */
-
-#ifndef _BUZ_H_
-#define _BUZ_H_
-
-/* The Buz only supports a maximum width of 720, but some V4L
-   applications (e.g. xawtv are more happy with 768).
-   If XAWTV_HACK is defined, we try to fake a device with bigger width */
-
-#define XAWTV_HACK
-
-#ifdef XAWTV_HACK
-#define   BUZ_MAX_WIDTH   768	/* never display more than 768 pixels */
-#else
-#define   BUZ_MAX_WIDTH   720	/* never display more than 720 pixels */
-#endif
-#define   BUZ_MAX_HEIGHT  576	/* never display more than 576 rows */
-#define   BUZ_MIN_WIDTH    32	/* never display less than 32 pixels */
-#define   BUZ_MIN_HEIGHT   24	/* never display less than 24 rows */
-
-struct zoran_requestbuffers {
-	unsigned long count;	/* Number of buffers for MJPEG grabbing */
-	unsigned long size;	/* Size PER BUFFER in bytes */
-};
-
-struct zoran_sync {
-	unsigned long frame;	/* number of buffer that has been free'd */
-	unsigned long length;	/* number of code bytes in buffer (capture only) */
-	unsigned long seq;	/* frame sequence number */
-	struct timeval timestamp;	/* timestamp */
-};
-
-struct zoran_status {
-	int input;		/* Input channel, has to be set prior to BUZIOC_G_STATUS */
-	int signal;		/* Returned: 1 if valid video signal detected */
-	int norm;		/* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
-	int color;		/* Returned: 1 if color signal detected */
-};
-
-struct zoran_params {
-
-	/* The following parameters can only be queried */
-
-	int major_version;	/* Major version number of driver */
-	int minor_version;	/* Minor version number of driver */
-
-	/* Main control parameters */
-
-	int input;		/* Input channel: 0 = Composite, 1 = S-VHS */
-	int norm;		/* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
-	int decimation;		/* decimation of captured video,
-				   enlargement of video played back.
-				   Valid values are 1, 2, 4 or 0.
-				   0 is a special value where the user
-				   has full control over video scaling */
-
-	/* The following parameters only have to be set if decimation==0,
-	   for other values of decimation they provide the data how the image is captured */
-
-	int HorDcm;		/* Horizontal decimation: 1, 2 or 4 */
-	int VerDcm;		/* Vertical decimation: 1 or 2 */
-	int TmpDcm;		/* Temporal decimation: 1 or 2,
-				   if TmpDcm==2 in capture every second frame is dropped,
-				   in playback every frame is played twice */
-	int field_per_buff;	/* Number of fields per buffer: 1 or 2 */
-	int img_x;		/* start of image in x direction */
-	int img_y;		/* start of image in y direction */
-	int img_width;		/* image width BEFORE decimation,
-				   must be a multiple of HorDcm*16 */
-	int img_height;		/* image height BEFORE decimation,
-				   must be a multiple of VerDcm*8 */
-
-	/* --- End of parameters for decimation==0 only --- */
-
-	/* JPEG control parameters */
-
-	int quality;		/* Measure for quality of compressed images.
-				   Scales linearly with the size of the compressed images.
-				   Must be beetween 0 and 100, 100 is a compression
-				   ratio of 1:4 */
-
-	int odd_even;		/* Which field should come first ??? */
-
-	int APPn;		/* Number of APP segment to be written, must be 0..15 */
-	int APP_len;		/* Length of data in JPEG APPn segment */
-	char APP_data[60];	/* Data in the JPEG APPn segment. */
-
-	int COM_len;		/* Length of data in JPEG COM segment */
-	char COM_data[60];	/* Data in JPEG COM segment */
-
-	unsigned long jpeg_markers;	/* Which markers should go into the JPEG output.
-					   Unless you exactly know what you do, leave them untouched.
-					   Inluding less markers will make the resulting code
-					   smaller, but there will be fewer aplications
-					   which can read it.
-					   The presence of the APP and COM marker is
-					   influenced by APP0_len and COM_len ONLY! */
-#define JPEG_MARKER_DHT (1<<3)	/* Define Huffman Tables */
-#define JPEG_MARKER_DQT (1<<4)	/* Define Quantization Tables */
-#define JPEG_MARKER_DRI (1<<5)	/* Define Restart Interval */
-#define JPEG_MARKER_COM (1<<6)	/* Comment segment */
-#define JPEG_MARKER_APP (1<<7)	/* App segment, driver will allways use APP0 */
-
-	int VFIFO_FB;		/* Flag for enabling Video Fifo Feedback.
-				   If this flag is turned on and JPEG decompressing
-				   is going to the screen, the decompress process
-				   is stopped every time the Video Fifo is full.
-				   This enables a smooth decompress to the screen
-				   but the video output signal will get scrambled */
-
-	/* Misc */
-
-	char reserved[312];	/* Makes 512 bytes for this structure */
-};
-
-/*
-   Private IOCTL to set up for displaying MJPEG
- */
-#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct zoran_params)
-#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct zoran_params)
-#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct zoran_requestbuffers)
-#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
-#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
-#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct zoran_sync)
-#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct zoran_status)
-
-
-#ifdef __KERNEL__
-
-#define BUZ_NUM_STAT_COM    4
-#define BUZ_MASK_STAT_COM   3
-
-#define BUZ_MAX_FRAME     256	/* Must be a power of 2 */
-#define BUZ_MASK_FRAME    255	/* Must be BUZ_MAX_FRAME-1 */
-
-#if VIDEO_MAX_FRAME <= 32
-#define   V4L_MAX_FRAME   32
-#elif VIDEO_MAX_FRAME <= 64
-#define   V4L_MAX_FRAME   64
-#else
-#error   "Too many video frame buffers to handle"
-#endif
-#define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
-
-
-#include "zr36057.h"
-
-enum zoran_codec_mode {
-	BUZ_MODE_IDLE,		/* nothing going on */
-	BUZ_MODE_MOTION_COMPRESS,	/* grabbing frames */
-	BUZ_MODE_MOTION_DECOMPRESS,	/* playing frames */
-	BUZ_MODE_STILL_COMPRESS,	/* still frame conversion */
-	BUZ_MODE_STILL_DECOMPRESS	/* still frame conversion */
-};
-
-enum zoran_buffer_state {
-	BUZ_STATE_USER,		/* buffer is owned by application */
-	BUZ_STATE_PEND,		/* buffer is queued in pend[] ready to feed to I/O */
-	BUZ_STATE_DMA,		/* buffer is queued in dma[] for I/O */
-	BUZ_STATE_DONE		/* buffer is ready to return to application */
-};
-
-struct zoran_gbuffer {
-	u32 *frag_tab;		/* addresses of frag table */
-	u32 frag_tab_bus;	/* same value cached to save time in ISR */
-	enum zoran_buffer_state state;	/* non-zero if corresponding buffer is in use in grab queue */
-	struct zoran_sync bs;	/* DONE: info to return to application */
-};
-
-struct v4l_gbuffer {
-	char *fbuffer;		/* virtual  address of frame buffer */
-	unsigned long fbuffer_phys;	/* physical address of frame buffer */
-	unsigned long fbuffer_bus;	/* bus      address of frame buffer */
-	enum zoran_buffer_state state;	/* state: unused/pending/done */
-};
-
-struct zoran {
-	struct video_device video_dev;
-	struct i2c_bus i2c;
-
-	int initialized;	/* flag if zoran has been correctly initalized */
-	int user;		/* number of current users (0 or 1) */
-
-	unsigned short id;	/* number of this device */
-	char name[32];		/* name of this device */
-	struct pci_dev *pci_dev;	/* PCI device */
-	unsigned char revision;		/* revision of zr36057 */
-	int board;			/* Board type */
-#define BOARD_BUZ		0
-#define BOARD_LML33		1	
-	unsigned int zr36057_adr;	/* bus address of IO mem returned by PCI BIOS */
-	unsigned char *zr36057_mem;	/* pointer to mapped IO memory */
-
-	int map_mjpeg_buffers;	/* Flag which bufferset will map by next mmap() */
-
-	spinlock_t lock;	/* Spinlock */
-
-	/* Video for Linux parameters */
-
-	struct video_picture picture;	/* Current picture params */
-	struct video_buffer buffer;	/* Current buffer params */
-	struct video_window window;	/* Current window params */
-	int buffer_set, window_set;	/* Flags if the above structures are set */
-	int video_interlace;	/* Image on screen is interlaced */
-
-	u32 *overlay_mask;
-
-	wait_queue_head_t v4l_capq;	/* wait here for grab to finish */
-
-	int v4l_overlay_active;	/* Overlay grab is activated */
-	int v4l_memgrab_active;	/* Memory grab is activated */
-
-	int v4l_grab_frame;	/* Frame number being currently grabbed */
-#define NO_GRAB_ACTIVE (-1)
-	int v4l_grab_seq;	/* Number of frames grabbed */
-	int gwidth;		/* Width of current memory capture */
-	int gheight;		/* Height of current memory capture */
-	int gformat;		/* Format of ... */
-	int gbpl;		/* byte per line of ... */
-
-	/* V4L grab queue of frames pending */
-
-	unsigned v4l_pend_head;
-	unsigned v4l_pend_tail;
-	int v4l_pend[V4L_MAX_FRAME];
-
-	struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME];	/* V4L   buffers' info */
-
-	/* Buz MJPEG parameters */
-
-	unsigned long jpg_nbufs;	/* Number of buffers */
-	unsigned long jpg_bufsize;	/* Size of mjpeg buffers in bytes */
-	int jpg_buffers_allocated;	/* Flag if buffers are allocated  */
-	int need_contiguous;	/* Flag if contiguous buffers are needed */
-
-	enum zoran_codec_mode codec_mode;		/* status of codec */
-	struct zoran_params params;	/* structure with a lot of things to play with */
-
-	wait_queue_head_t  jpg_capq;	/* wait here for grab to finish */
-
-	/* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */
-	/* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */
-	/* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */
-	unsigned long jpg_que_head;	/* Index where to put next buffer which is queued */
-	unsigned long jpg_dma_head;	/* Index of next buffer which goes into stat_com  */
-	unsigned long jpg_dma_tail;	/* Index of last buffer in stat_com               */
-	unsigned long jpg_que_tail;	/* Index of last buffer in queue                  */
-	unsigned long jpg_seq_num;	/* count of frames since grab/play started */
-
-	/* zr36057's code buffer table */
-	u32 *stat_com;		/* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
-
-	/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
-	int jpg_pend[BUZ_MAX_FRAME];
-
-	/* array indexed by frame number */
-	struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME];	/* MJPEG buffers' info */
-};
-
-#endif
-
-/*The following should be done in more portable way. It depends on define
-   of _ALPHA_BUZ in the Makefile. */
-
-#ifdef _ALPHA_BUZ
-#define btwrite(dat,adr)    writel((dat),(char *) (zr->zr36057_adr+(adr)))
-#define btread(adr)         readl(zr->zr36057_adr+(adr))
-#else
-#define btwrite(dat,adr)    writel((dat), (char *) (zr->zr36057_mem+(adr)))
-#define btread(adr)         readl(zr->zr36057_mem+(adr))
-#endif
-
-#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-#define I2C_TSA5522        0xc2
-#define I2C_TDA9850        0xb6
-#define I2C_HAUPEE         0xa0
-#define I2C_STBEE          0xae
-#define   I2C_SAA7111        0x48
-#define   I2C_SAA7185        0x88
-
-#define TDA9850_CON1       0x04
-#define TDA9850_CON2       0x05
-#define TDA9850_CON3       0x06
-#define TDA9850_CON4       0x07
-#define TDA9850_ALI1       0x08
-#define TDA9850_ALI2       0x09
-#define TDA9850_ALI3       0x0a
-
-#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/meye.c linux/drivers/media/video/meye.c
--- v2.4.6/linux/drivers/media/video/meye.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/meye.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,1498 @@
+/* 
+ * Motion Eye video4linux driver for Sony Vaio PictureBook
+ *
+ * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
+ * Some parts borrowed from various video4linux drivers, especially
+ * bttv-driver.c and zoran.c, see original files for credits.
+ * 
+ * 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/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/wrapper.h>
+#include <linux/interrupt.h>
+
+#include "meye.h"
+#include "linux/meye.h"
+
+/* driver structure - only one possible */
+static struct meye meye;
+/* number of grab buffers */
+static unsigned int gbuffers = 2;
+/* size of a grab buffer */
+static unsigned int gbufsize = MEYE_MAX_BUFSIZE;
+/* /dev/videoX registration number */
+static int video_nr = -1;
+
+/****************************************************************************/
+/* Queue routines                                                           */
+/****************************************************************************/
+
+/* Inits the queue */
+static inline void meye_initq(struct meye_queue *queue) {
+	queue->head = queue->tail = 0;
+	queue->len = 0;
+	queue->s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+	init_waitqueue_head(&queue->proc_list);
+}
+
+/* Pulls an element from the queue */
+static inline int meye_pullq(struct meye_queue *queue) {
+	int result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->s_lock, flags);
+	if (!queue->len) {
+		spin_unlock_irqrestore(&queue->s_lock, flags);
+		return -1;
+	}
+	result = queue->buf[queue->head];
+	queue->head++;
+	queue->head &= (MEYE_QUEUE_SIZE - 1);
+	queue->len--;
+	spin_unlock_irqrestore(&queue->s_lock, flags);
+	return result;
+}
+
+/* Pushes an element into the queue */
+static inline void meye_pushq(struct meye_queue *queue, int element) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->s_lock, flags);
+	if (queue->len == MEYE_QUEUE_SIZE) {
+		/* remove the first element */
+		queue->head++;
+		queue->head &= (MEYE_QUEUE_SIZE - 1);
+		queue->len--;
+	}
+	queue->buf[queue->tail] = element;
+	queue->tail++;
+	queue->tail &= (MEYE_QUEUE_SIZE - 1);
+	queue->len++;
+
+	spin_unlock_irqrestore(&queue->s_lock, flags);
+}
+
+/* Tests if the queue is empty */
+static inline int meye_emptyq(struct meye_queue *queue, int *elem) {
+	int result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->s_lock, flags);
+	result = (queue->len == 0);
+	if (!result && elem)
+		*elem = queue->buf[queue->head];
+	spin_unlock_irqrestore(&queue->s_lock, flags);
+	return result;
+}
+
+/****************************************************************************/
+/* Memory allocation routines (stolen from bttv-driver.c)                   */
+/****************************************************************************/
+
+#define MDEBUG(x)	do {} while (0)
+/* #define MDEBUG(x)	x */
+
+/* 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 = (unsigned long)page_address(pte_page(pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+				
+			}
+                }
+        }
+        MDEBUG(printk("uv2kva(%lx-->%lx)\n", 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)\n", 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)\n", 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)\n", adr, ret));
+        return ret;
+}
+
+static void *rvmalloc(signed long size) {
+	void *mem;
+	unsigned long adr, page;
+
+	mem = vmalloc_32(size);
+	if (mem) {
+		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(virt_to_page(__va(page)));
+			adr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, signed long size) {
+        unsigned long adr, page;
+        
+	if (mem) {
+	        adr = (unsigned long) mem;
+		while (size > 0) {
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/* return a page table pointing to N pages of locked memory */
+static void *ptable_alloc(int npages, u32 *pt_addr) {
+	int i = 0;
+	void *vmem;
+	u32 ptable[npages+1];
+	signed long size;
+	unsigned long adr;
+
+	size = (npages + 1) * PAGE_SIZE;
+	vmem = rvmalloc(size);
+	if (!vmem)
+		return NULL;
+
+	memset(ptable, 0, sizeof(ptable));
+        adr = (unsigned long)vmem;
+	while (size > 0) {
+		ptable[i++] = virt_to_bus(__va(kvirt_to_pa(adr)));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	memcpy(vmem + npages * PAGE_SIZE, ptable, PAGE_SIZE);
+	*pt_addr = ptable[npages];
+
+	return vmem;
+}
+
+static void ptable_free(void *vmem, int npages) {
+	rvfree(vmem, (npages + 1) * PAGE_SIZE);
+}
+
+/****************************************************************************/
+/* JPEG tables at different qualities to load into the VRJ chip             */
+/****************************************************************************/
+
+/* return a set of quantisation tables based on a quality from 1 to 10 */
+static u16 *jpeg_quantisation_tables(int *size, int quality) {
+	static u16 tables0[] = {
+		0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 
+		0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 
+	};
+	static u16 tables1[] = {
+		0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46, 
+		0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 
+		0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 
+		0xffff, 0xffff, 0xffff, 
+	};
+	static u16 tables2[] = {
+		0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23, 
+		0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164, 
+		0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad, 
+		0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff, 
+		0xe6ff, 0xfffd, 0xfff8, 
+		0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876, 
+		0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 
+		0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 
+		0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 
+		0xf8f8, 0xf8f8, 0xfff8, 
+	};
+	static u16 tables3[] = {
+		0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17, 
+		0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042, 
+		0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73, 
+		0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba, 
+		0x99c7, 0xaba8, 0xffa4, 
+		0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e, 
+		0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 
+		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 
+		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 
+		0xa4a4, 0xa4a4, 0xffa4, 
+	};
+	static u16 tables4[] = {
+		0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712, 
+		0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932, 
+		0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556, 
+		0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c, 
+		0x7396, 0x817e, 0xff7c, 
+		0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b, 
+		0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 
+		0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 
+		0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 
+		0x7c7c, 0x7c7c, 0xff7c, 
+	};
+	static u16 tables5[] = {
+		0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e, 
+		0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28, 
+		0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745, 
+		0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470, 
+		0x5c78, 0x6765, 0xff63, 
+		0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f, 
+		0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 
+		0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 
+		0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 
+		0x6363, 0x6363, 0xff63, 
+	};
+	static u16 tables6[] = {
+		0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b, 
+		0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20, 
+		0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37, 
+		0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a, 
+		0x4a60, 0x5251, 0xff4f, 
+		0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26, 
+		0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 
+		0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 
+		0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 
+		0x4f4f, 0x4f4f, 0xff4f, 
+	};
+	static u16 tables7[] = {
+		0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08, 
+		0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318, 
+		0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129, 
+		0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43, 
+		0x3748, 0x3e3d, 0xff3b, 
+		0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c, 
+		0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 
+		0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 
+		0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 
+		0x3b3b, 0x3b3b, 0xff3b, 
+	};
+	static u16 tables8[] = {
+		0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706, 
+		0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710, 
+		0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c, 
+		0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d, 
+		0x2530, 0x2928, 0xff28, 
+		0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813, 
+		0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 
+		0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 
+		0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 
+		0x2828, 0x2828, 0xff28, 
+	};
+	static u16 tables9[] = {
+		0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403, 
+		0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08, 
+		0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e, 
+		0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416, 
+		0x1218, 0x1514, 0xff14, 
+		0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409, 
+		0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 
+		0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 
+		0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 
+		0x1414, 0x1414, 0xff14, 
+	};
+	static u16 tables10[] = {
+		0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0xff01, 
+		0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0101, 0x0101, 0xff01, 
+	};
+
+	switch (quality) {
+	case 0:
+		*size = sizeof(tables0);
+		return tables0;
+	case 1:
+		*size = sizeof(tables1);
+		return tables1;
+	case 2:
+		*size = sizeof(tables2);
+		return tables2;
+	case 3:
+		*size = sizeof(tables3);
+		return tables3;
+	case 4:
+		*size = sizeof(tables4);
+		return tables4;
+	case 5:
+		*size = sizeof(tables5);
+		return tables5;
+	case 6:
+		*size = sizeof(tables6);
+		return tables6;
+	case 7:
+		*size = sizeof(tables7);
+		return tables7;
+	case 8:
+		*size = sizeof(tables8);
+		return tables8;
+	case 9:
+		*size = sizeof(tables9);
+		return tables9;
+	case 10:
+		*size = sizeof(tables10);
+		return tables10;
+	default:
+		printk(KERN_WARNING "meye: invalid quality level %d - using 8\n", quality);
+		*size = sizeof(tables8);
+		return tables8;
+	}
+	return NULL;
+}
+
+/* return a generic set of huffman tables */
+static u16 *jpeg_huffman_tables(int *size) {
+	static u16 tables[] = {
+		0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405, 
+		0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131, 
+		0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142, 
+		0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918, 
+		0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443, 
+		0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463, 
+		0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483, 
+		0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A, 
+		0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, 
+		0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6, 
+		0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2, 
+		0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, 
+		0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405, 
+		0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206, 
+		0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1, 
+		0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125, 
+		0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A, 
+		0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A, 
+		0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A, 
+		0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 
+		0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 
+		0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 
+		0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2, 
+		0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, 
+		0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000, 
+		0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, 
+		0xFF0B, 
+		0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101, 
+		0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, 
+		0xFF0B
+	};
+
+	*size = sizeof(tables);
+	return tables;
+}
+
+/****************************************************************************/
+/* MCHIP low-level functions                                                */
+/****************************************************************************/
+
+/* waits for the specified miliseconds */
+static inline void wait_ms(unsigned int ms) {
+	if (!in_interrupt()) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1 + ms * HZ / 1000);
+	}
+	else
+		mdelay(ms);
+}
+
+/* returns the horizontal capture size */
+static inline int mchip_hsize(void) {
+	return meye.params.subsample ? 320 : 640;
+}
+
+/* returns the vertical capture size */
+static inline int mchip_vsize(void) {
+	return meye.params.subsample ? 240 : 480;
+}
+
+/* waits for a register to be available */
+static void mchip_sync(int reg) {
+	u32 status;
+	int i;
+
+	if (reg == MCHIP_MM_FIFO_DATA) {
+		for (i = 0; i < MCHIP_REG_TIMEOUT; i++) {
+			status = readl(meye.mchip_mmregs + MCHIP_MM_FIFO_STATUS);
+			if (!(status & MCHIP_MM_FIFO_WAIT)) {
+				printk(KERN_WARNING "meye: fifo not ready\n");
+				return;
+			}
+			if (status & MCHIP_MM_FIFO_READY)
+				return;
+			udelay(1);
+		}
+	}
+	else if (reg > 0x80) {
+		u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY
+			                 : MCHIP_HIC_STATUS_VRJ_RDY;
+		for (i = 0; i < MCHIP_REG_TIMEOUT; i++) {
+			status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS);
+			if (status & mask)
+				return;
+			udelay(1);
+		}
+	}
+	else
+		return;
+	printk(KERN_WARNING "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", reg, status);
+}
+
+/* sets a value into the register */
+static inline void mchip_set(int reg, u32 v) {
+	mchip_sync(reg);
+	writel(v, meye.mchip_mmregs + reg);
+}
+
+/* get the register value */
+static inline u32 mchip_read(int reg) {
+	mchip_sync(reg);
+	return readl(meye.mchip_mmregs + reg);
+}
+
+/* wait for a register to become a particular value */
+static inline int mchip_delay(u32 reg, u32 v) {
+	int n = 10;
+	while (--n && mchip_read(reg) != v) 
+		udelay(1);
+	return n;
+}
+
+/* setup subsampling */
+static void mchip_subsample(void) {
+	mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample);
+	mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize());
+	mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize());
+	mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize());
+	mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize());
+	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
+}
+
+/* set the framerate into the mchip */
+static void mchip_set_framerate(void) {
+	mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate);
+}
+
+/* load some huffman and quantisation tables into the VRJ chip ready
+   for JPEG compression */
+static void mchip_load_tables(void) {
+	int i;
+	int size;
+	u16 *tables;
+
+	tables = jpeg_huffman_tables(&size);
+	for (i = 0; i < size / 2; i++)
+		writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);
+
+	tables = jpeg_quantisation_tables(&size, meye.params.quality);
+	for (i = 0; i < size / 2; i++)
+		writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);
+}
+
+/* setup the VRJ parameters in the chip */
+static void mchip_vrj_setup(u8 mode) {
+
+	mchip_set(MCHIP_VRJ_BUS_MODE, 5);
+	mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f);
+	mchip_set(MCHIP_VRJ_PDAT_USE, 1);
+	mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0);
+	mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode);
+	mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize());
+	mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize());
+	mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b);
+	mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF);
+	mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF);
+	mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC);
+	mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0);
+	mchip_set(MCHIP_VRJ_SOF1, 0x601);
+	mchip_set(MCHIP_VRJ_SOF2, 0x1502);
+	mchip_set(MCHIP_VRJ_SOF3, 0x1503);
+	mchip_set(MCHIP_VRJ_SOF4, 0x1596);
+	mchip_set(MCHIP_VRJ_SOS,  0x0ed0);
+
+	mchip_load_tables();
+}
+
+/* setup for DMA transfers - also zeros the framebuffer */
+static int mchip_dma_alloc(void) {
+	if (!meye.mchip_fbuffer) {
+		meye.mchip_fbuffer = ptable_alloc(MCHIP_NB_PAGES, 
+				                  &meye.mchip_ptaddr);
+		if (!meye.mchip_fbuffer)
+			return -1;
+	}
+	return 0;
+}
+
+/* frees the DMA buffer */
+static void mchip_dma_free(void) {
+	if (meye.mchip_fbuffer) {
+		ptable_free(meye.mchip_fbuffer, MCHIP_NB_PAGES);
+		meye.mchip_fbuffer = 0;
+		meye.mchip_ptaddr = 0;
+	}
+}
+
+/* sets the DMA parameters into the chip */
+static void mchip_dma_setup(void) {
+	int i;
+
+	mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_ptaddr);
+	for (i = 0; i < 4; i++)
+		mchip_set(MCHIP_MM_FIR(i), 0);
+	meye.mchip_fnum = 0;
+}
+
+/* stop any existing HIC action and wait for any dma to complete then
+   reset the dma engine */
+static void mchip_hic_stop(void) {
+	int i = 0;
+
+	meye.mchip_mode = MCHIP_HIC_MODE_NOOP;
+	if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) 
+		return;
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP);
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	while (!mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) {
+		/*  resetting HIC */
+		mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP);
+		mchip_delay(MCHIP_HIC_CMD, 0);
+		mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET);
+		wait_ms(250);
+		if (i++ > 20) {
+			printk(KERN_ERR "meye: resetting HIC hanged!\n");
+			break;
+		}
+	}
+	wait_ms(100);
+}
+
+/****************************************************************************/
+/* MCHIP frame processing functions                                         */
+/****************************************************************************/
+
+/* get the next ready frame from the dma engine */
+static u32 mchip_get_frame(void) {
+	u32 v;
+	
+	v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum));
+	return v;
+}
+
+/* frees the current frame from the dma engine */
+static void mchip_free_frame(void) {
+	mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0);
+	meye.mchip_fnum++;
+	meye.mchip_fnum %= 4;
+}
+
+
+/* read one frame from the framebuffer assuming it was captured using
+   a uncompressed transfer */
+static void  mchip_cont_read_frame(u32 v, u8 *buf, int size) {
+	int pt_id;
+	int avail;
+
+	pt_id = (v >> 17) & 0x3FF;
+	avail = MCHIP_NB_PAGES - pt_id;
+
+	if (size > avail*PAGE_SIZE) {
+		memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, 
+		       avail * PAGE_SIZE);
+		memcpy(buf +avail * PAGE_SIZE, meye.mchip_fbuffer,
+		       size - avail * PAGE_SIZE);
+	}
+	else
+		memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, size);
+}
+
+/* read a compressed frame from the framebuffer */
+static int mchip_comp_read_frame(u32 v, u8 *buf, int size) {
+	int pt_start, pt_end, trailer;
+	int fsize, fsize2;
+	int i;
+
+	pt_start = (v >> 19) & 0xFF;
+	pt_end = (v >> 11) & 0xFF;
+	trailer = (v >> 1) & 0x3FF;
+
+	if (pt_end < pt_start) {
+		fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE;
+		fsize2 = pt_end * PAGE_SIZE + trailer * 4;
+		if (fsize + fsize2 > size) {
+			printk(KERN_WARNING "meye: oversized compressed frame %d %d\n", 
+			       fsize, fsize2);
+			return -1;
+		} else {
+			memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, 
+			       fsize);
+			memcpy(buf + fsize, meye.mchip_fbuffer, fsize2); 
+			fsize += fsize2;
+		}
+	} else {
+		fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4;
+		if (fsize > size) {
+			printk(KERN_WARNING "meye: oversized compressed frame %d\n", 
+			       fsize);
+			return -1;
+		} else
+			memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, 
+			       fsize);
+	}
+
+
+#ifdef MEYE_JPEG_CORRECTION
+
+	/* Some mchip generated jpeg frames are incorrect. In most
+	 * (all ?) of those cases, the final EOI (0xff 0xd9) marker 
+	 * is not present at the end of the frame.
+	 *
+	 * Since adding the final marker is not enough to restore
+	 * the jpeg integrity, we drop the frame.
+	 */
+
+	for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ;
+
+	if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9)
+		return -1;
+
+#endif
+
+	return fsize;
+}
+
+/* take a picture into SDRAM */
+static void mchip_take_picture(void) {
+	int i;
+	
+	mchip_hic_stop();
+	mchip_subsample();
+	mchip_dma_setup();
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+
+	for (i = 0; i < 100; ++i) {
+		if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
+			break;
+		wait_ms(1);
+	}
+}
+
+/* dma a previously taken picture into a buffer */
+static void mchip_get_picture(u8 *buf, int bufsize) {
+	u32 v;
+	int i;
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	for (i = 0; i < 100; ++i) {
+		if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
+			break;
+		wait_ms(1);
+	}
+	for (i = 0; i < 4 ; ++i) {
+		v = mchip_get_frame();
+		if (v & MCHIP_MM_FIR_RDY) {
+			mchip_cont_read_frame(v, buf, bufsize);
+			break;
+		}
+		mchip_free_frame();
+	}
+}
+
+/* start continuous dma capture */
+static void mchip_continuous_start(void) {
+	mchip_hic_stop();
+	mchip_subsample();
+	mchip_set_framerate();
+	mchip_dma_setup();
+
+	meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+}
+
+/* compress one frame into a buffer */
+static int mchip_compress_frame(u8 *buf, int bufsize) {
+	u32 v;
+	int len = -1, i;
+
+	mchip_vrj_setup(0x3f);
+	udelay(50);
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+	
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	for (i = 0; i < 100; ++i) {
+		if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
+			break;
+		wait_ms(1);
+	}
+
+	for (i = 0; i < 4 ; ++i) {
+		v = mchip_get_frame();
+		if (v & MCHIP_MM_FIR_RDY) {
+			len = mchip_comp_read_frame(v, buf, bufsize);
+			break;
+		}
+		mchip_free_frame();
+	}
+	return len;
+}
+
+#if 0
+/* uncompress one image into a buffer */
+static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) {
+	mchip_vrj_setup(0x3f);
+	udelay(50);
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+	
+	mchip_delay(MCHIP_HIC_CMD, 0);
+
+	return mchip_comp_read_frame(buf, bufsize);
+}
+#endif
+
+/* start continuous compressed capture */
+static void mchip_cont_compression_start(void) {
+	mchip_hic_stop();
+	mchip_vrj_setup(0x3f);
+	mchip_subsample();
+	mchip_set_framerate();
+	mchip_dma_setup();
+
+	meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
+
+	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP);
+	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+}
+
+/****************************************************************************/
+/* Interrupt handling                                                       */
+/****************************************************************************/
+
+static void meye_irq(int irq, void *dev_id, struct pt_regs *regs) {
+	u32 v;
+	int reqnr;
+	v = mchip_read(MCHIP_MM_INTA);
+
+	while (1) {
+		v = mchip_get_frame();
+		if (!(v & MCHIP_MM_FIR_RDY))
+			goto out;
+		switch (meye.mchip_mode) {
+
+		case MCHIP_HIC_MODE_CONT_OUT:
+			if (!meye_emptyq(&meye.grabq, NULL)) {
+				int nr = meye_pullq(&meye.grabq);
+				mchip_cont_read_frame(
+					v, 
+					meye.grab_fbuffer + gbufsize * nr,
+					mchip_hsize() * mchip_vsize() * 2);
+				meye.grab_buffer[nr].state = MEYE_BUF_DONE;
+				wake_up_interruptible(&meye.grabq.proc_list);
+			}
+			break;
+
+		case MCHIP_HIC_MODE_CONT_COMP:
+			if (!meye_emptyq(&meye.grabq, &reqnr)) {
+				int size;
+				size = mchip_comp_read_frame(
+					v,
+					meye.grab_fbuffer + gbufsize * reqnr,
+					gbufsize);
+				if (size == -1)
+					break;
+				reqnr = meye_pullq(&meye.grabq);
+				meye.grab_buffer[reqnr].size = size;
+				meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
+				wake_up_interruptible(&meye.grabq.proc_list);
+			}
+			break;
+
+		default:
+			/* do not free frame, since it can be a snap */
+			goto out;
+		} /* switch */
+
+		mchip_free_frame();
+	}
+out:
+}
+
+/****************************************************************************/
+/* video4linux integration                                                  */
+/****************************************************************************/
+
+static int meye_open(struct video_device *dev, int flags) {
+	int i;
+
+	down(&meye.lock);
+	if (meye.open_count) {
+		up(&meye.lock);
+		return -EBUSY;
+	}
+	meye.open_count++;
+	if (mchip_dma_alloc()) {
+		printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
+		up(&meye.lock);
+		return -ENOBUFS;
+	}
+	mchip_hic_stop();
+	meye_initq(&meye.grabq);
+	for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
+		meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+	up(&meye.lock);
+	return 0;
+}
+
+static void meye_close(struct video_device *dev) {
+	down(&meye.lock);
+	meye.open_count--;
+	mchip_hic_stop();
+	up(&meye.lock);
+}
+
+static int meye_ioctl(struct video_device *dev, unsigned int cmd, void *arg) {
+
+	switch (cmd) {
+
+	case VIDIOCGCAP: {
+		struct video_capability b;
+		strcpy(b.name,meye.video_dev.name);
+		b.type = VID_TYPE_CAPTURE;
+		b.channels = 1;
+		b.audios = 0;
+		b.maxwidth = 640;
+		b.maxheight = 480;
+		b.minwidth = 320;
+		b.minheight = 240;
+		if(copy_to_user(arg,&b,sizeof(b)))
+			return -EFAULT;
+		break;
+	}
+
+	case VIDIOCGCHAN: {
+		struct video_channel v;
+		if(copy_from_user(&v, arg,sizeof(v)))
+			return -EFAULT;
+		v.flags = 0;
+		v.tuners = 0;
+		v.type = VIDEO_TYPE_CAMERA;
+		if (v.channel != 0)
+			return -EINVAL;
+		strcpy(v.name,"Camera");
+		if(copy_to_user(arg,&v,sizeof(v)))
+			return -EFAULT;
+		break;
+	}
+
+	case VIDIOCSCHAN: {
+		struct video_channel v;
+		if(copy_from_user(&v, arg,sizeof(v)))
+			return -EFAULT;
+		if (v.channel != 0)
+			return -EINVAL;
+		break;
+	}
+
+	case VIDIOCGPICT: {
+		struct video_picture p = meye.picture;
+		if(copy_to_user(arg, &p, sizeof(p)))
+			return -EFAULT;
+		break;
+	}
+
+	case VIDIOCSPICT: {
+		struct video_picture p;
+		if(copy_from_user(&p, arg,sizeof(p)))
+			return -EFAULT;
+		if (p.depth != 2)
+			return -EINVAL;
+		if (p.palette != VIDEO_PALETTE_YUV422)
+			return -EINVAL;
+		down(&meye.lock);
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 
+				      p.brightness >> 10);
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 
+				      p.hue >> 10);
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 
+				      p.colour >> 10);
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 
+				      p.contrast >> 10);
+		memcpy(&meye.picture, &p, sizeof(p));
+		up(&meye.lock);
+		break;
+	}
+
+	case VIDIOCSYNC: {
+		int i;
+		DECLARE_WAITQUEUE(wait, current);
+
+		if(copy_from_user((void *)&i,arg,sizeof(int)))
+			return -EFAULT;
+		if (i < 0 || i >= gbuffers)
+			return -EINVAL;
+
+		switch (meye.grab_buffer[i].state) {
+
+		case MEYE_BUF_UNUSED:
+			return -EINVAL;
+		case MEYE_BUF_USING:
+			add_wait_queue(&meye.grabq.proc_list, &wait);
+			current->state = TASK_INTERRUPTIBLE;
+			while (meye.grab_buffer[i].state == MEYE_BUF_USING) {
+				schedule();
+				if(signal_pending(current)) {
+					remove_wait_queue(&meye.grabq.proc_list, &wait);
+					current->state = TASK_RUNNING;
+					return -EINTR;
+				}
+			}
+			remove_wait_queue(&meye.grabq.proc_list, &wait);
+			current->state = TASK_RUNNING;
+			/* fall through */
+		case MEYE_BUF_DONE:
+			meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+		}
+		break;
+	}
+
+	case VIDIOCMCAPTURE: {
+		struct video_mmap vm;
+		int restart = 0;
+
+		if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
+			return -EFAULT;
+		if (vm.frame >= gbuffers || vm.frame < 0)
+			return -EINVAL;
+		if (vm.format != VIDEO_PALETTE_YUV422)
+			return -EINVAL;
+		if (vm.height * vm.width * 2 > gbufsize)
+			return -EINVAL;
+		if (!meye.grab_fbuffer)
+			return -EINVAL;
+		if (meye.grab_buffer[vm.frame].state != MEYE_BUF_UNUSED)
+			return -EBUSY;
+
+		down(&meye.lock);
+		if (vm.width == 640 && vm.height == 480) {
+			if (meye.params.subsample) {
+				meye.params.subsample = 0;
+				restart = 1;
+			}
+		}
+		else if (vm.width == 320 && vm.height == 240) {
+			if (!meye.params.subsample) {
+				meye.params.subsample = 1;
+				restart = 1;
+			}
+		}
+		else {
+			up(&meye.lock);
+			return -EINVAL;
+		}
+
+		if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT)
+			mchip_continuous_start();
+		meye.grab_buffer[vm.frame].state = MEYE_BUF_USING;
+		meye_pushq(&meye.grabq, vm.frame);
+		up(&meye.lock);
+		break;
+	}
+
+	case VIDIOCGMBUF: {
+		struct video_mbuf vm;
+		int i;
+
+		memset(&vm, 0 , sizeof(vm));
+		vm.size = gbufsize * gbuffers;
+		vm.frames = gbuffers;
+		for (i = 0; i < gbuffers; i++)
+			vm.offsets[i] = i * gbufsize;
+		if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			return -EFAULT;
+		break;
+	}
+
+	case MEYEIOC_G_PARAMS: {
+		if (copy_to_user(arg, &meye.params, sizeof(meye.params)))
+			return -EFAULT;
+		break;
+	}
+
+	case MEYEIOC_S_PARAMS: {
+		struct meye_params jp;
+		if (copy_from_user(&jp, arg, sizeof(jp)))
+			return -EFAULT;
+		if (jp.subsample > 1)
+			return -EINVAL;
+		if (jp.quality > 10)
+			return -EINVAL;
+		if (jp.sharpness > 63 || jp.agc > 63 || jp.picture > 63)
+			return -EINVAL;
+		if (jp.framerate > 31)
+			return -EINVAL;
+		down(&meye.lock);
+		if (meye.params.subsample != jp.subsample ||
+		    meye.params.quality != jp.quality)
+			mchip_hic_stop();	/* need restart */
+		memcpy(&meye.params, &jp, sizeof(jp));
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS,
+				      meye.params.sharpness);
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC,
+				      meye.params.agc);
+		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
+				      meye.params.picture);
+		up(&meye.lock);
+		break;
+	}
+
+	case MEYEIOC_QBUF_CAPT: {
+		int nb;
+
+		if (copy_from_user((void *) &nb, (void *) arg, sizeof(int)))
+			return -EFAULT;
+
+		if (!meye.grab_fbuffer) 
+			return -EINVAL;
+		if (nb >= gbuffers)
+			return -EINVAL;
+		if (nb < 0) {
+			/* stop capture */
+			mchip_hic_stop();
+			return 0;
+		}
+		if (meye.grab_buffer[nb].state != MEYE_BUF_UNUSED)
+			return -EBUSY;
+		down(&meye.lock);
+		if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
+			mchip_cont_compression_start();
+		meye.grab_buffer[nb].state = MEYE_BUF_USING;
+		meye_pushq(&meye.grabq, nb);
+		up(&meye.lock);
+		break;
+	}
+
+	case MEYEIOC_SYNC: {
+		int i;
+		DECLARE_WAITQUEUE(wait, current);
+
+		if(copy_from_user((void *)&i,arg,sizeof(int)))
+			return -EFAULT;
+		if (i < 0 || i >= gbuffers)
+			return -EINVAL;
+
+		switch (meye.grab_buffer[i].state) {
+
+		case MEYE_BUF_UNUSED:
+			return -EINVAL;
+		case MEYE_BUF_USING:
+			add_wait_queue(&meye.grabq.proc_list, &wait);
+			current->state = TASK_INTERRUPTIBLE;
+			while (meye.grab_buffer[i].state == MEYE_BUF_USING) {
+				schedule();
+				if(signal_pending(current)) {
+					remove_wait_queue(&meye.grabq.proc_list, &wait);
+					current->state = TASK_RUNNING;
+					return -EINTR;
+				}
+			}
+			remove_wait_queue(&meye.grabq.proc_list, &wait);
+			current->state = TASK_RUNNING;
+			/* fall through */
+		case MEYE_BUF_DONE:
+			meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+		}
+		i = meye.grab_buffer[i].size;
+		if (copy_to_user(arg, (void *)&i, sizeof(int)))
+			return -EFAULT;
+		break;
+	}
+
+	case MEYEIOC_STILLCAPT: {
+
+		if (!meye.grab_fbuffer) 
+			return -EINVAL;
+		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+			return -EBUSY;
+		down(&meye.lock);
+		meye.grab_buffer[0].state = MEYE_BUF_USING;
+		mchip_take_picture();
+		mchip_get_picture(
+			meye.grab_fbuffer,
+			mchip_hsize() * mchip_vsize() * 2);
+		meye.grab_buffer[0].state = MEYE_BUF_DONE;
+		up(&meye.lock);
+		break;
+	}
+
+	case MEYEIOC_STILLJCAPT: {
+		int len = -1;
+
+		if (!meye.grab_fbuffer) 
+			return -EINVAL;
+		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+			return -EBUSY;
+		down(&meye.lock);
+		meye.grab_buffer[0].state = MEYE_BUF_USING;
+		while (len == -1) {
+			mchip_take_picture();
+			len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
+		}
+		meye.grab_buffer[0].state = MEYE_BUF_DONE;
+		up(&meye.lock);
+		if (copy_to_user(arg, (void *)&len, sizeof(int)))
+			return -EFAULT;
+		break;
+	}
+
+	default:
+		return -ENOIOCTLCMD;
+		
+	} /* switch */
+
+	return 0;
+}
+
+static int meye_mmap(struct video_device *dev, const char *adr, 
+		     unsigned long size) {
+	unsigned long start=(unsigned long) adr;
+	unsigned long page,pos;
+
+	down(&meye.lock);
+	if (size > gbuffers * gbufsize) {
+		up(&meye.lock);
+		return -EINVAL;
+	}
+	if (!meye.grab_fbuffer) {
+		/* lazy allocation */
+		meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
+		if (!meye.grab_fbuffer) {
+			printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
+			up(&meye.lock);
+			return -ENOMEM;
+		}
+	}
+	pos = (unsigned long)meye.grab_fbuffer;
+
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+			up(&meye.lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	up(&meye.lock);
+	return 0;
+}
+
+static struct video_device meye_template = {
+	owner:		THIS_MODULE,
+	name:		"meye",
+	type:		VID_TYPE_CAPTURE,
+	hardware:	VID_HARDWARE_MEYE,
+	open:		meye_open,
+	close:		meye_close,
+	ioctl:		meye_ioctl,
+	mmap:		meye_mmap,
+};
+
+static int __devinit meye_probe(struct pci_dev *pcidev, 
+		                const struct pci_device_id *ent) {
+	int ret;
+	unsigned long mchip_adr;
+	u8 revision;
+
+	if (meye.mchip_dev != NULL) {
+		printk(KERN_ERR "meye: only one device allowed!\n");
+		ret = -EBUSY;
+		goto out1;
+	}
+
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1);
+
+	meye.mchip_dev = pcidev;
+	meye.mchip_irq = pcidev->irq;
+	memcpy(&meye.video_dev, &meye_template, sizeof(meye_template));
+
+	if (mchip_dma_alloc()) {
+		printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
+		ret = -ENOMEM;
+		goto out2;
+	}
+
+	if ((ret = pci_enable_device(meye.mchip_dev))) {
+		printk(KERN_ERR "meye: pci_enable_device failed\n");
+		goto out3;
+	}
+
+	mchip_adr = pci_resource_start(meye.mchip_dev,0);
+	if (!mchip_adr) {
+		printk(KERN_ERR "meye: mchip has no device base address\n");
+		ret = -EIO;
+		goto out4;
+	}
+	if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0),
+			        pci_resource_len(meye.mchip_dev, 0),
+				"meye")) {
+		ret = -EIO;
+		printk(KERN_ERR "meye: request_mem_region failed\n");
+		goto out4;
+	}
+
+	pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision);
+
+	pci_set_master(meye.mchip_dev);
+
+	pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8);
+	pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64);
+
+	if ((ret = request_irq(meye.mchip_irq, meye_irq, 
+			       SA_INTERRUPT | SA_SHIRQ, "meye", meye_irq))) {
+		printk(KERN_ERR "meye: request_irq failed (ret=%d)\n", ret);
+		goto out5;
+	}
+
+	meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);
+	if (!meye.mchip_mmregs) {
+		printk(KERN_ERR "meye: ioremap failed\n");
+		ret = -EIO;
+		goto out6;
+	}
+	
+	/* Ask the camera to perform a soft reset. */
+	pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);
+
+	mchip_delay(MCHIP_HIC_CMD, 0);
+	mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
+
+	wait_ms(1);
+	mchip_set(MCHIP_VRJ_SOFT_RESET, 1);
+
+	wait_ms(1);
+	mchip_set(MCHIP_MM_PCI_MODE, 5);
+
+	wait_ms(1);
+	mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
+
+	if (video_register_device(&meye.video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {
+
+		printk(KERN_ERR "meye: video_register_device failed\n");
+		ret = -EIO;
+		goto out7;
+	}
+	
+	printk(KERN_INFO "meye: Motion Eye Camera Driver v%d.%d.\n",
+	       MEYE_DRIVER_MAJORVERSION,
+	       MEYE_DRIVER_MINORVERSION);
+	printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n", 
+		revision, mchip_adr, meye.mchip_irq);
+
+	/* init all fields */
+	init_MUTEX(&meye.lock);
+
+	meye.picture.depth = 2;
+	meye.picture.palette = VIDEO_PALETTE_YUV422;
+	meye.picture.brightness = 32 << 10;
+	meye.picture.hue = 32 << 10;
+	meye.picture.colour = 32 << 10;
+	meye.picture.contrast = 32 << 10;
+	meye.picture.whiteness = 0;
+	meye.params.subsample = 0;
+	meye.params.quality = 7;
+	meye.params.sharpness = 32;
+	meye.params.agc = 48;
+	meye.params.picture = 0;
+	meye.params.framerate = 0;
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32);
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32);
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32);
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32);
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32);
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0);
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
+
+	return 0;
+out7:
+	iounmap(meye.mchip_mmregs);
+out6:
+	free_irq(meye.mchip_irq, meye_irq);
+out5:
+	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
+			   pci_resource_len(meye.mchip_dev, 0));
+out4:
+	pci_disable_device(meye.mchip_dev);
+out3:
+	mchip_dma_free();
+out2:
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+out1:
+	return ret;
+}
+
+static void __devexit meye_remove(struct pci_dev *pcidev) {
+
+	video_unregister_device(&meye.video_dev);
+
+	mchip_hic_stop();
+
+	/* disable interrupts */
+	mchip_set(MCHIP_MM_INTA, 0x0);
+
+	free_irq(meye.mchip_irq, meye_irq);
+
+
+	iounmap(meye.mchip_mmregs);
+
+	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
+			   pci_resource_len(meye.mchip_dev, 0));
+
+	pci_disable_device(meye.mchip_dev);
+
+	mchip_dma_free();
+
+	if (meye.grab_fbuffer)
+		rvfree(meye.grab_fbuffer, gbuffers*gbufsize);
+
+	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+
+	printk(KERN_INFO "meye: removed\n");
+}
+
+static struct pci_device_id meye_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002, 
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, meye_pci_tbl);
+
+static struct pci_driver meye_driver = {
+	name:		"meye",
+	id_table:	meye_pci_tbl,
+	probe:		meye_probe,
+	remove:		meye_remove,
+};
+
+static int __init meye_init_module(void) {
+	if (gbuffers < 2)
+		gbuffers = 2;
+	if (gbuffers > MEYE_MAX_BUFNBRS)
+		gbuffers = MEYE_MAX_BUFNBRS;
+	if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)
+		gbufsize = MEYE_MAX_BUFSIZE;
+	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n",
+	       gbuffers, gbufsize/1024, gbuffers*gbufsize/1024);
+	return pci_module_init(&meye_driver);
+}
+
+static void __exit meye_cleanup_module(void) {
+	pci_unregister_driver(&meye_driver);
+}
+
+MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_DESCRIPTION("video4linux driver for the MotionEye camera");
+
+MODULE_PARM(gbuffers,"i");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (32 max)");
+MODULE_PARM(gbufsize,"i");
+MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 614400");
+MODULE_PARM(video_nr,"i");
+MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+
+/* Module entry points */
+module_init(meye_init_module);
+module_exit(meye_cleanup_module);
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/meye.h linux/drivers/media/video/meye.h
--- v2.4.6/linux/drivers/media/video/meye.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/meye.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,313 @@
+/* 
+ * Motion Eye video4linux driver for Sony Vaio PictureBook
+ *
+ * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ * 
+ * Some parts borrowed from various video4linux drivers, especially
+ * bttv-driver.c and zoran.c, see original files for credits.
+ * 
+ * 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 _MEYE_PRIV_H_
+#define _MEYE_PRIV_H_
+
+#define MEYE_DRIVER_MAJORVERSION	1
+#define MEYE_DRIVER_MINORVERSION	0
+
+/****************************************************************************/
+/* Motion JPEG chip registers                                               */
+/****************************************************************************/
+
+/* Motion JPEG chip PCI configuration registers */
+#define MCHIP_PCI_POWER_CSR		0x54
+#define MCHIP_PCI_MCORE_STATUS		0x60	/* see HIC_STATUS   */
+#define MCHIP_PCI_HOSTUSEREQ_SET	0x64
+#define MCHIP_PCI_HOSTUSEREQ_CLR	0x68
+#define MCHIP_PCI_LOWPOWER_SET		0x6c
+#define MCHIP_PCI_LOWPOWER_CLR		0x70
+#define MCHIP_PCI_SOFTRESET_SET		0x74
+
+/* Motion JPEG chip memory mapped registers */
+#define MCHIP_MM_REGS			0x200		/* 512 bytes        */
+#define MCHIP_REG_TIMEOUT		1000		/* reg access, ~us  */
+#define MCHIP_MCC_VRJ_TIMEOUT		1000		/* MCC & VRJ access */
+
+#define MCHIP_MM_PCI_MODE		0x00		/* PCI access mode */
+#define MCHIP_MM_PCI_MODE_RETRY		0x00000001	/* retry mode */
+#define MCHIP_MM_PCI_MODE_MASTER	0x00000002	/* master access */
+#define MCHIP_MM_PCI_MODE_READ_LINE	0x00000004	/* read line */
+
+#define MCHIP_MM_INTA			0x04		/* Int status/mask */
+#define MCHIP_MM_INTA_MCC		0x00000001	/* MCC interrupt */
+#define MCHIP_MM_INTA_VRJ		0x00000002	/* VRJ interrupt */
+#define MCHIP_MM_INTA_HIC_1		0x00000004	/* one frame done */
+#define MCHIP_MM_INTA_HIC_1_MASK	0x00000400	/* 1: enable */
+#define MCHIP_MM_INTA_HIC_END		0x00000008	/* all frames done */
+#define MCHIP_MM_INTA_HIC_END_MASK	0x00000800
+#define MCHIP_MM_INTA_JPEG		0x00000010	/* decompress. error */
+#define MCHIP_MM_INTA_JPEG_MASK		0x00001000
+#define MCHIP_MM_INTA_CAPTURE		0x00000020	/* capture end */
+#define MCHIP_MM_INTA_PCI_ERR		0x00000040	/* PCI error */
+#define MCHIP_MM_INTA_PCI_ERR_MASK	0x00004000
+
+#define MCHIP_MM_PT_ADDR		0x08		/* page table address */
+							/* n*4kB */
+#define MCHIP_NB_PAGES			1024		/* pages for display */
+#define MCHIP_NB_PAGES_MJPEG		256		/* pages for mjpeg */
+
+#define MCHIP_MM_FIR(n)			(0x0c+(n)*4)	/* Frame info 0-3 */
+#define MCHIP_MM_FIR_RDY		0x00000001	/* frame ready */
+#define MCHIP_MM_FIR_FAILFR_MASK	0xf8000000	/* # of failed frames */
+#define MCHIP_MM_FIR_FAILFR_SHIFT	27
+
+	/* continuous comp/decomp mode */
+#define MCHIP_MM_FIR_C_ENDL_MASK	0x000007fe	/* end DW [10] */
+#define MCHIP_MM_FIR_C_ENDL_SHIFT	1
+#define MCHIP_MM_FIR_C_ENDP_MASK	0x0007f800	/* end page [8] */
+#define MCHIP_MM_FIR_C_ENDP_SHIFT	11
+#define MCHIP_MM_FIR_C_STARTP_MASK	0x07f80000	/* start page [8] */
+#define MCHIP_MM_FIR_C_STARTP_SHIFT	19
+
+	/* continuous picture output mode */
+#define MCHIP_MM_FIR_O_STARTP_MASK	0x7ffe0000	/* start page [10] */
+#define MCHIP_MM_FIR_O_STARTP_SHIFT	17
+
+#define MCHIP_MM_FIFO_DATA		0x1c		/* PCI TGT FIFO data */
+#define MCHIP_MM_FIFO_STATUS		0x20		/* PCI TGT FIFO stat */
+#define MCHIP_MM_FIFO_MASK		0x00000003
+#define MCHIP_MM_FIFO_WAIT_OR_READY	0x00000002      /* Bits common to WAIT & READY*/
+#define MCHIP_MM_FIFO_IDLE		0x0		/* HIC idle */
+#define MCHIP_MM_FIFO_IDLE1		0x1		/* idem ??? */
+#define	MCHIP_MM_FIFO_WAIT		0x2		/* wait request */
+#define MCHIP_MM_FIFO_READY		0x3		/* data ready */
+
+#define MCHIP_HIC_HOST_USEREQ		0x40		/* host uses MCORE */
+
+#define MCHIP_HIC_TP_BUSY		0x44		/* taking picture */
+
+#define MCHIP_HIC_PIC_SAVED		0x48		/* pic in SDRAM */
+
+#define MCHIP_HIC_LOWPOWER		0x4c		/* clock stopped */
+
+#define MCHIP_HIC_CTL			0x50		/* HIC control */
+#define MCHIP_HIC_CTL_SOFT_RESET	0x00000001	/* MCORE reset */
+#define MCHIP_HIC_CTL_MCORE_RDY		0x00000002	/* MCORE ready */
+
+#define MCHIP_HIC_CMD			0x54		/* HIC command */
+#define MCHIP_HIC_CMD_BITS		0x00000003      /* cmd width=[1:0]*/
+#define MCHIP_HIC_CMD_NOOP		0x0
+#define MCHIP_HIC_CMD_START		0x1
+#define MCHIP_HIC_CMD_STOP		0x2
+
+#define MCHIP_HIC_MODE			0x58
+#define MCHIP_HIC_MODE_NOOP		0x0
+#define MCHIP_HIC_MODE_STILL_CAP	0x1		/* still pic capt */
+#define MCHIP_HIC_MODE_DISPLAY		0x2		/* display */
+#define MCHIP_HIC_MODE_STILL_COMP	0x3		/* still pic comp. */
+#define MCHIP_HIC_MODE_STILL_DECOMP	0x4		/* still pic decomp. */
+#define MCHIP_HIC_MODE_CONT_COMP	0x5		/* cont capt+comp */
+#define MCHIP_HIC_MODE_CONT_DECOMP	0x6		/* cont decomp+disp */
+#define MCHIP_HIC_MODE_STILL_OUT	0x7		/* still pic output */
+#define MCHIP_HIC_MODE_CONT_OUT		0x8		/* cont output */
+
+#define MCHIP_HIC_STATUS		0x5c
+#define MCHIP_HIC_STATUS_MCC_RDY	0x00000001	/* MCC reg acc ok */
+#define MCHIP_HIC_STATUS_VRJ_RDY	0x00000002	/* VRJ reg acc ok */
+#define MCHIP_HIC_STATUS_IDLE           0x00000003
+#define MCHIP_HIC_STATUS_CAPDIS		0x00000004	/* cap/disp in prog */
+#define MCHIP_HIC_STATUS_COMPDEC	0x00000008	/* (de)comp in prog */
+#define MCHIP_HIC_STATUS_BUSY		0x00000010	/* HIC busy */
+
+#define MCHIP_HIC_S_RATE		0x60		/* MJPEG # frames */
+
+#define MCHIP_HIC_PCI_VFMT		0x64		/* video format */
+#define MCHIP_HIC_PCI_VFMT_YVYU		0x00000001	/* 0: V Y' U Y */
+							/* 1: Y' V Y U */
+
+#define MCHIP_MCC_CMD			0x80		/* MCC commands */
+#define MCHIP_MCC_CMD_INITIAL		0x0		/* idle ? */
+#define MCHIP_MCC_CMD_IIC_START_SET	0x1
+#define MCHIP_MCC_CMD_IIC_END_SET	0x2
+#define MCHIP_MCC_CMD_FM_WRITE		0x3		/* frame memory */
+#define MCHIP_MCC_CMD_FM_READ		0x4
+#define MCHIP_MCC_CMD_FM_STOP		0x5
+#define MCHIP_MCC_CMD_CAPTURE		0x6
+#define MCHIP_MCC_CMD_DISPLAY		0x7
+#define MCHIP_MCC_CMD_END_DISP		0x8
+#define MCHIP_MCC_CMD_STILL_COMP	0x9
+#define MCHIP_MCC_CMD_STILL_DECOMP	0xa
+#define MCHIP_MCC_CMD_STILL_OUTPUT	0xb
+#define MCHIP_MCC_CMD_CONT_OUTPUT	0xc
+#define MCHIP_MCC_CMD_CONT_COMP		0xd
+#define MCHIP_MCC_CMD_CONT_DECOMP	0xe
+#define MCHIP_MCC_CMD_RESET		0xf		/* MCC reset */
+
+#define MCHIP_MCC_IIC_WR		0x84
+
+#define MCHIP_MCC_MCC_WR		0x88
+
+#define MCHIP_MCC_MCC_RD		0x8c
+
+#define MCHIP_MCC_STATUS		0x90
+#define MCHIP_MCC_STATUS_CAPT		0x00000001	/* capturing */
+#define MCHIP_MCC_STATUS_DISP		0x00000002	/* displaying */
+#define MCHIP_MCC_STATUS_COMP		0x00000004	/* compressing */
+#define MCHIP_MCC_STATUS_DECOMP		0x00000008	/* decompressing */
+#define MCHIP_MCC_STATUS_MCC_WR		0x00000010	/* register ready */
+#define MCHIP_MCC_STATUS_MCC_RD		0x00000020	/* register ready */
+#define MCHIP_MCC_STATUS_IIC_WR		0x00000040	/* register ready */
+#define MCHIP_MCC_STATUS_OUTPUT		0x00000080	/* output in prog */
+
+#define MCHIP_MCC_SIG_POLARITY		0x94
+#define MCHIP_MCC_SIG_POL_VS_H		0x00000001	/* VS active-high */
+#define MCHIP_MCC_SIG_POL_HS_H		0x00000002	/* HS active-high */
+#define MCHIP_MCC_SIG_POL_DOE_H		0x00000004	/* DOE active-high */
+
+#define MCHIP_MCC_IRQ			0x98
+#define MCHIP_MCC_IRQ_CAPDIS_STRT	0x00000001	/* cap/disp started */
+#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK	0x00000010
+#define MCHIP_MCC_IRQ_CAPDIS_END	0x00000002	/* cap/disp ended */
+#define MCHIP_MCC_IRQ_CAPDIS_END_MASK	0x00000020
+#define MCHIP_MCC_IRQ_COMPDEC_STRT	0x00000004	/* (de)comp started */
+#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK	0x00000040
+#define MCHIP_MCC_IRQ_COMPDEC_END	0x00000008	/* (de)comp ended */
+#define MCHIP_MCC_IRQ_COMPDEC_END_MASK	0x00000080
+
+#define MCHIP_MCC_HSTART		0x9c		/* video in */
+#define MCHIP_MCC_VSTART		0xa0
+#define MCHIP_MCC_HCOUNT		0xa4
+#define MCHIP_MCC_VCOUNT		0xa8
+#define MCHIP_MCC_R_XBASE		0xac		/* capt/disp */
+#define MCHIP_MCC_R_YBASE		0xb0
+#define MCHIP_MCC_R_XRANGE		0xb4
+#define MCHIP_MCC_R_YRANGE		0xb8
+#define MCHIP_MCC_B_XBASE		0xbc		/* comp/decomp */
+#define MCHIP_MCC_B_YBASE		0xc0
+#define MCHIP_MCC_B_XRANGE		0xc4
+#define MCHIP_MCC_B_YRANGE		0xc8
+
+#define MCHIP_MCC_R_SAMPLING		0xcc		/* 1: 1:4 */
+
+#define MCHIP_VRJ_CMD			0x100		/* VRJ commands */
+
+/* VRJ registers (see table 12.2.4) */
+#define MCHIP_VRJ_COMPRESSED_DATA	0x1b0
+#define MCHIP_VRJ_PIXEL_DATA		0x1b8
+
+#define MCHIP_VRJ_BUS_MODE		0x100
+#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL	0x108
+#define MCHIP_VRJ_PDAT_USE		0x110
+#define MCHIP_VRJ_MODE_SPECIFY		0x118
+#define MCHIP_VRJ_LIMIT_COMPRESSED_LO	0x120
+#define MCHIP_VRJ_LIMIT_COMPRESSED_HI	0x124
+#define MCHIP_VRJ_COMP_DATA_FORMAT	0x128
+#define MCHIP_VRJ_TABLE_DATA		0x140
+#define MCHIP_VRJ_RESTART_INTERVAL	0x148
+#define MCHIP_VRJ_NUM_LINES		0x150
+#define MCHIP_VRJ_NUM_PIXELS		0x158
+#define MCHIP_VRJ_NUM_COMPONENTS	0x160
+#define MCHIP_VRJ_SOF1			0x168
+#define MCHIP_VRJ_SOF2			0x170
+#define MCHIP_VRJ_SOF3			0x178
+#define MCHIP_VRJ_SOF4			0x180
+#define MCHIP_VRJ_SOS			0x188
+#define MCHIP_VRJ_SOFT_RESET		0x190
+
+#define MCHIP_VRJ_STATUS		0x1c0
+#define MCHIP_VRJ_STATUS_BUSY		0x00001
+#define MCHIP_VRJ_STATUS_COMP_ACCESS	0x00002
+#define MCHIP_VRJ_STATUS_PIXEL_ACCESS	0x00004
+#define MCHIP_VRJ_STATUS_ERROR		0x00008
+
+#define MCHIP_VRJ_IRQ_FLAG		0x1c8
+#define MCHIP_VRJ_ERROR_REPORT		0x1d8
+
+#define MCHIP_VRJ_START_COMMAND		0x1a0
+
+/****************************************************************************/
+/* Driver definitions.                                                      */
+/****************************************************************************/
+
+/* Sony Programmable I/O Controller for accessing the camera commands */
+#include <linux/sonypi.h>
+
+/* private API definitions */
+#include <linux/meye.h>
+
+/* Enable jpg software correction */
+#define MEYE_JPEG_CORRECTION	1
+
+/* Maximum size of a buffer */
+#define MEYE_MAX_BUFSIZE	614400	/* 640 * 480 * 2 */
+
+/* Maximum number of buffers */
+#define MEYE_MAX_BUFNBRS	32
+
+/* State of a buffer */
+#define MEYE_BUF_UNUSED	0	/* not used */
+#define MEYE_BUF_USING	1	/* currently grabbing / playing */
+#define MEYE_BUF_DONE	2	/* done */
+
+/* grab buffer */
+struct meye_grab_buffer {
+	int state;			/* state of buffer */
+	unsigned long size;		/* size of jpg frame */
+};
+
+/* queues containing the buffer indices */
+#define MEYE_QUEUE_SIZE	MEYE_MAX_BUFNBRS
+struct meye_queue {
+	unsigned int head;		/* queue head */
+	unsigned int tail;		/* queue tail */
+	unsigned int len;		/* queue length */
+	spinlock_t s_lock;		/* spinlock protecting the queue */
+	wait_queue_head_t proc_list;	/* wait queue */
+	int buf[MEYE_QUEUE_SIZE];	/* queue contents */
+};
+
+/* Motion Eye device structure */
+struct meye {
+
+	/* mchip related */
+	struct pci_dev *mchip_dev;	/* pci device */
+	u8 mchip_irq;			/* irq */
+	u8 mchip_mode;			/* actual mchip mode: HIC_MODE... */
+	u8 mchip_fnum;			/* current mchip frame number */
+
+	unsigned char *mchip_mmregs;	/* mchip: memory mapped registers */
+	unsigned char *mchip_fbuffer;	/* mchip: framebuffer */
+	u32 mchip_ptaddr;		/* mchip: pointer to framebuffer */
+
+	unsigned char *grab_fbuffer;	/* capture framebuffer */
+					/* list of buffers */
+	struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
+
+	/* other */
+	unsigned int open_count;	/* open() count */
+	struct semaphore lock;		/* semaphore for open/mmap... */
+
+	struct meye_queue grabq;	/* queue for buffers to be grabbed */
+
+	struct video_device video_dev;	/* video device parameters */
+	struct video_picture picture;	/* video picture parameters */
+	struct meye_params params;	/* additional parameters */
+};
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c
--- v2.4.6/linux/drivers/media/video/saa5249.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/saa5249.c	Wed Jul  4 14:41:33 2001
@@ -102,6 +102,7 @@
 	int disp_mode;
 	int virtual_mode;
 	struct i2c_client *client;
+	struct semaphore lock;
 };
 
 
@@ -175,6 +176,7 @@
 	}
 	memset(t, 0, sizeof(*t));
 	strcpy(client->name, IF_NAME);
+	init_MUTEX(&t->lock);
 	
 	/*
 	 *	Now create a video4linux device
@@ -188,7 +190,7 @@
 		return -ENOMEM;
 	}
 	memcpy(vd, &saa_template, sizeof(*vd));
-	
+		
 	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) 
 	{
 		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
@@ -199,7 +201,8 @@
 		t->vdau[pgbuf].stopped = TRUE;
 		t->is_searching[pgbuf] = FALSE;
 	}
-	vd->priv=t;		 
+	vd->priv=t;	
+	 
 	
 	/*
 	 *	Register it
@@ -342,9 +345,8 @@
  *	Standard character-device-driver functions
  */
 
-static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg) 
+static int do_saa5249_ioctl(struct saa5249_device *t, unsigned int cmd, void *arg) 
 {
-	struct saa5249_device *t=vd->priv;
 	static int virtual_mode = FALSE;
 
 	switch(cmd) 
@@ -602,6 +604,21 @@
 	return -EINVAL;
 }
 
+/*
+ *	Handle the locking
+ */
+ 
+static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg) 
+{
+	struct saa5249_device *t=vd->priv;
+	int err;
+	
+	down(&t->lock);
+	err = do_saa5249_ioctl(t, cmd, arg);
+	up(&t->lock);
+
+	return err;
+}
 
 static int saa5249_open(struct video_device *vd, int nb) 
 {
@@ -632,7 +649,6 @@
 		t->is_searching[pgbuf] = FALSE;
 	}
 	t->virtual_mode=FALSE;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -643,7 +659,6 @@
 	struct saa5249_device *t=vd->priv;
 	i2c_senddata(t, 1, 0x20, -1);		/* Turn off CCT */
 	i2c_senddata(t, 5, 3, 3, -1);		/* Turn off TV-display */
-	MOD_DEC_USE_COUNT;
 	return;
 }
 
@@ -669,6 +684,7 @@
 
 static struct video_device saa_template =
 {
+	owner:		THIS_MODULE,
 	name:		IF_NAME,
 	type:		VID_TYPE_TELETEXT,	/*| VID_TYPE_TUNER ?? */
 	hardware:	VID_HARDWARE_SAA5249,
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zoran.h linux/drivers/media/video/zoran.h
--- v2.4.6/linux/drivers/media/video/zoran.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/zoran.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,372 @@
+/* 
+    zoran - Iomega Buz driver
+
+    Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+   based on
+
+    zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   and
+
+    bttv - Bt848 frame grabber driver
+    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.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.
+*/
+
+#ifndef _BUZ_H_
+#define _BUZ_H_
+
+#include <linux/config.h>
+
+#if LINUX_VERSION_CODE < 0x20212
+typedef struct wait_queue *wait_queue_head_t;
+#endif
+
+/* The Buz only supports a maximum width of 720, but some V4L
+   applications (e.g. xawtv are more happy with 768).
+   If XAWTV_HACK is defined, we try to fake a device with bigger width */
+
+//#define XAWTV_HACK
+
+//#ifdef XAWTV_HACK
+//#define   BUZ_MAX_WIDTH   768   /* never display more than 768 pixels */
+#define   BUZ_MAX_WIDTH   (zr->timing->Wa)
+//#else
+//#define   BUZ_MAX_WIDTH   720   /* never display more than 720 pixels */
+//#endif
+//#define   BUZ_MAX_HEIGHT  576   /* never display more than 576 rows */
+#define   BUZ_MAX_HEIGHT  (zr->timing->Ha)
+#define   BUZ_MIN_WIDTH    32	/* never display less than 32 pixels */
+#define   BUZ_MIN_HEIGHT   24	/* never display less than 24 rows */
+
+struct zoran_requestbuffers {
+	unsigned long count;	/* Number of buffers for MJPEG grabbing */
+	unsigned long size;	/* Size PER BUFFER in bytes */
+};
+
+struct zoran_sync {
+	unsigned long frame;	/* number of buffer that has been free'd */
+	unsigned long length;	/* number of code bytes in buffer (capture only) */
+	unsigned long seq;	/* frame sequence number */
+	struct timeval timestamp;	/* timestamp */
+};
+
+struct zoran_status {
+	int input;		/* Input channel, has to be set prior to BUZIOC_G_STATUS */
+	int signal;		/* Returned: 1 if valid video signal detected */
+	int norm;		/* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int color;		/* Returned: 1 if color signal detected */
+};
+
+struct zoran_params {
+
+	/* The following parameters can only be queried */
+
+	int major_version;	/* Major version number of driver */
+	int minor_version;	/* Minor version number of driver */
+
+	/* Main control parameters */
+
+	int input;		/* Input channel: 0 = Composite, 1 = S-VHS */
+	int norm;		/* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int decimation;		/* decimation of captured video,
+				   enlargement of video played back.
+				   Valid values are 1, 2, 4 or 0.
+				   0 is a special value where the user
+				   has full control over video scaling */
+
+	/* The following parameters only have to be set if decimation==0,
+	   for other values of decimation they provide the data how the image is captured */
+
+	int HorDcm;		/* Horizontal decimation: 1, 2 or 4 */
+	int VerDcm;		/* Vertical decimation: 1 or 2 */
+	int TmpDcm;		/* Temporal decimation: 1 or 2,
+				   if TmpDcm==2 in capture every second frame is dropped,
+				   in playback every frame is played twice */
+	int field_per_buff;	/* Number of fields per buffer: 1 or 2 */
+	int img_x;		/* start of image in x direction */
+	int img_y;		/* start of image in y direction */
+	int img_width;		/* image width BEFORE decimation,
+				   must be a multiple of HorDcm*16 */
+	int img_height;		/* image height BEFORE decimation,
+				   must be a multiple of VerDcm*8 */
+
+	/* --- End of parameters for decimation==0 only --- */
+
+	/* JPEG control parameters */
+
+	int quality;		/* Measure for quality of compressed images.
+				   Scales linearly with the size of the compressed images.
+				   Must be beetween 0 and 100, 100 is a compression
+				   ratio of 1:4 */
+
+	int odd_even;		/* Which field should come first ??? */
+
+	int APPn;		/* Number of APP segment to be written, must be 0..15 */
+	int APP_len;		/* Length of data in JPEG APPn segment */
+	char APP_data[60];	/* Data in the JPEG APPn segment. */
+
+	int COM_len;		/* Length of data in JPEG COM segment */
+	char COM_data[60];	/* Data in JPEG COM segment */
+
+	unsigned long jpeg_markers;	/* Which markers should go into the JPEG output.
+					   Unless you exactly know what you do, leave them untouched.
+					   Inluding less markers will make the resulting code
+					   smaller, but there will be fewer aplications
+					   which can read it.
+					   The presence of the APP and COM marker is
+					   influenced by APP0_len and COM_len ONLY! */
+#define JPEG_MARKER_DHT (1<<3)	/* Define Huffman Tables */
+#define JPEG_MARKER_DQT (1<<4)	/* Define Quantization Tables */
+#define JPEG_MARKER_DRI (1<<5)	/* Define Restart Interval */
+#define JPEG_MARKER_COM (1<<6)	/* Comment segment */
+#define JPEG_MARKER_APP (1<<7)	/* App segment, driver will allways use APP0 */
+
+	int VFIFO_FB;		/* Flag for enabling Video Fifo Feedback.
+				   If this flag is turned on and JPEG decompressing
+				   is going to the screen, the decompress process
+				   is stopped every time the Video Fifo is full.
+				   This enables a smooth decompress to the screen
+				   but the video output signal will get scrambled */
+
+	/* Misc */
+
+	char reserved[312];	/* Makes 512 bytes for this structure */
+};
+
+/*
+Private IOCTL to set up for displaying MJPEG
+*/
+#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct zoran_params)
+#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct zoran_params)
+#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct zoran_requestbuffers)
+#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
+#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
+#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct zoran_sync)
+#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct zoran_status)
+
+
+#ifdef __KERNEL__
+
+#define BUZ_NUM_STAT_COM    4
+#define BUZ_MASK_STAT_COM   3
+
+#define BUZ_MAX_FRAME     256	/* Must be a power of 2 */
+#define BUZ_MASK_FRAME    255	/* Must be BUZ_MAX_FRAME-1 */
+
+#if VIDEO_MAX_FRAME <= 32
+#   define   V4L_MAX_FRAME   32
+#elif VIDEO_MAX_FRAME <= 64
+#   define   V4L_MAX_FRAME   64
+#else
+#   error   "Too many video frame buffers to handle"
+#endif
+#define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
+
+
+#include "zr36057.h"
+
+enum card_type {
+        UNKNOWN = 0,
+        DC10,
+        DC10plus,
+        LML33,
+        BUZ
+};
+
+enum zoran_codec_mode {
+	BUZ_MODE_IDLE,		/* nothing going on */
+	BUZ_MODE_MOTION_COMPRESS,	/* grabbing frames */
+	BUZ_MODE_MOTION_DECOMPRESS,	/* playing frames */
+	BUZ_MODE_STILL_COMPRESS,	/* still frame conversion */
+	BUZ_MODE_STILL_DECOMPRESS	/* still frame conversion */
+};
+
+enum zoran_buffer_state {
+	BUZ_STATE_USER,		/* buffer is owned by application */
+	BUZ_STATE_PEND,		/* buffer is queued in pend[] ready to feed to I/O */
+	BUZ_STATE_DMA,		/* buffer is queued in dma[] for I/O */
+	BUZ_STATE_DONE		/* buffer is ready to return to application */
+};
+
+struct zoran_gbuffer {
+	u32 *frag_tab;		/* addresses of frag table */
+	u32 frag_tab_bus;	/* same value cached to save time in ISR */
+	enum zoran_buffer_state state;	/* non-zero if corresponding buffer is in use in grab queue */
+	struct zoran_sync bs;	/* DONE: info to return to application */
+};
+
+struct v4l_gbuffer {
+	char *fbuffer;			/* virtual  address of frame buffer */
+	unsigned long fbuffer_phys;	/* physical address of frame buffer */
+	unsigned long fbuffer_bus;	/* bus      address of frame buffer */
+	enum zoran_buffer_state state;	/* state: unused/pending/done */
+};
+
+struct tvnorm {
+	u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+};
+
+struct zoran {
+	struct video_device video_dev;
+	struct i2c_bus i2c;
+
+	int initialized;		/* flag if zoran has been correctly initalized */
+	int user;			/* number of current users (0 or 1) */
+        enum card_type card;
+        struct tvnorm *timing;
+
+	unsigned short id;		/* number of this device */
+	char name[32];			/* name of this device */
+	struct pci_dev *pci_dev;	/* PCI device */
+	unsigned char revision;		/* revision of zr36057 */
+	unsigned int zr36057_adr;	/* bus address of IO mem returned by PCI BIOS */
+	unsigned char *zr36057_mem;	/* pointer to mapped IO memory */
+
+	int map_mjpeg_buffers;		/* Flag which bufferset will map by next mmap() */
+
+	spinlock_t lock;		/* Spinlock irq and hardware */
+	struct semaphore sem;		/* Guard parallel ioctls and mmap */
+
+	/* Video for Linux parameters */
+
+	struct video_picture picture;	/* Current picture params */
+	struct video_buffer buffer;	/* Current buffer params */
+	struct video_window window;	/* Current window params */
+	int buffer_set, window_set;	/* Flags if the above structures are set */
+	int video_interlace;		/* Image on screen is interlaced */
+
+	u32 *overlay_mask;
+        wait_queue_head_t v4l_capq;
+
+	int v4l_overlay_active;		/* Overlay grab is activated */
+	int v4l_memgrab_active;		/* Memory grab is activated */
+
+	int v4l_grab_frame;		/* Frame number being currently grabbed */
+#define NO_GRAB_ACTIVE (-1)
+	int v4l_grab_seq;		/* Number of frames grabbed */
+	int gwidth;			/* Width of current memory capture */
+	int gheight;			/* Height of current memory capture */
+	int gformat;			/* Format of ... */
+	int gbpl;			/* byte per line of ... */
+
+	/* V4L grab queue of frames pending */
+
+	unsigned v4l_pend_head;
+	unsigned v4l_pend_tail;
+	int v4l_pend[V4L_MAX_FRAME];
+
+	struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME];	/* V4L   buffers' info */
+
+	/* Buz MJPEG parameters */
+
+	unsigned long jpg_nbufs;	/* Number of buffers */
+	unsigned long jpg_bufsize;	/* Size of mjpeg buffers in bytes */
+	int jpg_buffers_allocated;	/* Flag if buffers are allocated  */
+	int need_contiguous;	/* Flag if contiguous buffers are needed */
+
+	enum zoran_codec_mode codec_mode;	/* status of codec */
+	struct zoran_params params;	/* structure with a lot of things to play with */
+
+	wait_queue_head_t jpg_capq;	/* wait here for grab to finish */
+
+	/* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */
+	/* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */
+	/* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */
+	unsigned long jpg_que_head;	/* Index where to put next buffer which is queued */
+	unsigned long jpg_dma_head;	/* Index of next buffer which goes into stat_com  */
+	unsigned long jpg_dma_tail;	/* Index of last buffer in stat_com               */
+	unsigned long jpg_que_tail;	/* Index of last buffer in queue                  */
+	unsigned long jpg_seq_num;	/* count of frames since grab/play started        */
+	unsigned long jpg_err_seq;	/* last seq_num before error                      */
+	unsigned long jpg_err_shift;
+	unsigned long jpg_queued_num;	/* count of frames queued since grab/play started */
+
+	/* zr36057's code buffer table */
+	u32 *stat_com;			/* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+
+	/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
+	int jpg_pend[BUZ_MAX_FRAME];
+
+	/* array indexed by frame number */
+	struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME];	/* MJPEG buffers' info */
+
+	/* Additional stuff for testing */
+	struct proc_dir_entry *zoran_proc;
+
+	int testing;
+	int jpeg_error;
+	int intr_counter_GIRQ1;
+	int intr_counter_GIRQ0;
+	int intr_counter_CodRepIRQ;
+	int intr_counter_JPEGRepIRQ;
+	int field_counter;
+	int IRQ1_in;
+	int IRQ1_out;
+	int JPEG_in;
+	int JPEG_out;
+	int JPEG_0;
+	int JPEG_1;
+	int END_event_missed;
+	int JPEG_missed;
+	int JPEG_error;
+	int num_errors;
+	int JPEG_max_missed;
+	int JPEG_min_missed;
+
+	u32 last_isr;
+	unsigned long frame_num;
+
+	wait_queue_head_t test_q;
+};
+
+#endif
+
+/*The following should be done in more portable way. It depends on define
+  of _ALPHA_BUZ in the Makefile.*/
+
+#ifdef _ALPHA_BUZ
+#define btwrite(dat,adr)    writel((dat),(char *) (zr->zr36057_adr+(adr)))
+#define btread(adr)         readl(zr->zr36057_adr+(adr))
+#else
+#define btwrite(dat,adr)    writel((dat), (char *) (zr->zr36057_mem+(adr)))
+#define btread(adr)         readl(zr->zr36057_mem+(adr))
+#endif
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#define I2C_TSA5522        0xc2
+#define I2C_TDA9850        0xb6
+#define I2C_HAUPEE         0xa0
+#define I2C_STBEE          0xae
+#define   I2C_SAA7111        0x48
+#define   I2C_SAA7110        0x9c
+#define   I2C_SAA7185        0x88
+//#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7175        0x54
+
+#define TDA9850_CON1       0x04
+#define TDA9850_CON2       0x05
+#define TDA9850_CON3       0x06
+#define TDA9850_CON4       0x07
+#define TDA9850_ALI1       0x08
+#define TDA9850_ALI2       0x09
+#define TDA9850_ALI3       0x0a
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zoran_procfs.c linux/drivers/media/video/zoran_procfs.c
--- v2.4.6/linux/drivers/media/video/zoran_procfs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/zoran_procfs.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,170 @@
+#include <linux/config.h>
+#include <linux/ctype.h>
+
+struct procfs_params_zr36067 {
+	char *name;
+	short reg;
+	u32 mask;
+	short bit;
+};
+
+static struct procfs_params_zr36067 zr67[] = {
+	{"HSPol", 0x000, 1, 30},
+	{"HStart", 0x000, 0x3ff, 10},
+	{"HEnd", 0x000, 0x3ff, 0},
+
+	{"VSPol", 0x004, 1, 30},
+	{"VStart", 0x004, 0x3ff, 10},
+	{"VEnd", 0x004, 0x3ff, 0},
+
+	{"ExtFl", 0x008, 1, 26},
+	{"TopField", 0x008, 1, 25},
+	{"VCLKPol", 0x008, 1, 24},
+	{"DupFld", 0x008, 1, 20},
+	{"LittleEndian", 0x008, 1, 0},
+
+	{"HsyncStart", 0x10c, 0xffff, 16},
+	{"LineTot", 0x10c, 0xffff, 0},
+
+	{"NAX", 0x110, 0xffff, 16},
+	{"PAX", 0x110, 0xffff, 0},
+
+	{"NAY", 0x114, 0xffff, 16},
+	{"PAY", 0x114, 0xffff, 0},
+/*    {"",,,}, */
+
+	{NULL, 0, 0, 0},
+};
+
+static void setparam(struct zoran *zr, char *name, char *sval)
+{
+	int i, reg0, reg, val;
+	i = 0;
+	while (zr67[i].name != NULL) {
+		if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) {
+			reg = reg0 = btread(zr67[i].reg);
+			reg &= ~(zr67[i].mask << zr67[i].bit);
+			if (!isdigit(sval[0]))
+				break;
+			val = simple_strtoul(sval, NULL, 0);
+			if ((val & ~zr67[i].mask))
+				break;
+			reg |= (val & zr67[i].mask) << zr67[i].bit;
+			printk(KERN_INFO "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n",
+			       zr->name, zr67[i].reg, reg0, reg, zr67[i].name, val);
+			btwrite(reg, zr67[i].reg);
+			break;
+		}
+		i++;
+	}
+}
+
+/* This macro was stolen from /usr/src/drivers/char/nvram.c and modified */
+#define	PRINT_PROC(args...)					\
+	do {							\
+		if (begin + len > offset + size) {		\
+			*eof = 0;                               \
+                        break;				        \
+		}                                               \
+                len += sprintf( buffer+len, ##args );	        \
+		if (begin + len < offset) {			\
+			begin += len;				\
+			len = 0;				\
+		}						\
+	} while(0)
+
+static int zoran_read_proc(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
+{
+#ifdef CONFIG_PROC_FS
+	int len = 0;
+	off_t begin = 0;
+
+	int i;
+	struct zoran *zr;
+
+	zr = (struct zoran *) data;
+	DEBUG2(printk(KERN_INFO "%s: read_proc: buffer=%x, offset=%d, size=%d, data=%x\n", zr->name, (int) buffer, (int) offset, size, (int) data));
+	*eof = 1;
+	PRINT_PROC("ZR36067 registers:");
+	for (i = 0; i < 0x130; i += 4) {
+		if (!(i % 16)) {
+			PRINT_PROC("\n%03X", i);
+		}
+		PRINT_PROC(" %08X ", btread(i));
+	}
+	PRINT_PROC("\n");
+	if (offset >= len + begin) {
+		return 0;
+	}
+	*start = buffer + begin - offset;
+	return ((size < begin + len - offset) ? size : begin + len - offset);
+#endif
+	return 0;
+}
+
+static int zoran_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+#ifdef CONFIG_PROC_FS
+	char *string, *sp;
+	char *line, *ldelim, *varname, *svar, *tdelim;
+	struct zoran *zr;
+
+	zr = (struct zoran *) data;
+
+	string = sp = vmalloc(count + 1);
+	if (!string) {
+		printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name);
+		return -ENOMEM;
+	}
+	memcpy(string, buffer, count);
+	string[count] = 0;
+	DEBUG2(printk(KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n", zr->name, file->f_dentry->d_name.name, count, (int) data));
+	ldelim = " \t\n";
+	tdelim = "=";
+	line = strpbrk(sp, ldelim);
+	while (line) {
+		*line = 0;
+		svar = strpbrk(sp, tdelim);
+		if (svar) {
+			*svar = 0;
+			varname = sp;
+			svar++;
+			setparam(zr, varname, svar);
+		}
+		sp = line + 1;
+		line = strpbrk(sp, ldelim);
+	}
+	vfree(string);
+#endif
+	return count;
+}
+
+static int zoran_proc_init(int i)
+{
+#ifdef CONFIG_PROC_FS
+	char name[8];
+	sprintf(name, "zoran%d", i);
+	if ((zoran[i].zoran_proc = create_proc_entry(name, 0, 0))) {
+		zoran[i].zoran_proc->read_proc = zoran_read_proc;
+		zoran[i].zoran_proc->write_proc = zoran_write_proc;
+		zoran[i].zoran_proc->data = &zoran[i];
+		printk(KERN_INFO "%s: procfs entry /proc/%s allocated. data=%x\n", zoran[i].name, name, (int) zoran[i].zoran_proc->data);
+	} else {
+		printk(KERN_ERR "%s: Unable to initialise /proc/%s\n", zoran[i].name, name);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+static void zoran_proc_cleanup(int i)
+{
+#ifdef CONFIG_PROC_FS
+	char name[8];
+	sprintf(name, "zoran%d", i);
+	if (zoran[i].zoran_proc) {
+		remove_proc_entry(name, 0);
+	}
+	zoran[i].zoran_proc = NULL;
+#endif
+}
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36057.h linux/drivers/media/video/zr36057.h
--- v2.4.6/linux/drivers/media/video/zr36057.h	Mon Jul  5 20:09:40 1999
+++ linux/drivers/media/video/zr36057.h	Wed Jul  4 14:41:33 2001
@@ -1,22 +1,22 @@
 /* 
-   zr36057.h - zr36057 register offsets
+    zr36057.h - zr36057 register offsets
 
-   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.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.
- */
+    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 _ZR36057_H_
 #define _ZR36057_H_
@@ -24,19 +24,19 @@
 
 /* Zoran ZR36057 registers */
 
-#define ZR36057_VFEHCR          0x000	/* Video Front End, Horizontal Configuration Register */
+#define ZR36057_VFEHCR          0x000   /* Video Front End, Horizontal Configuration Register */
 #define ZR36057_VFEHCR_HSPol            (1<<30)
 #define ZR36057_VFEHCR_HStart           10
 #define ZR36057_VFEHCR_HEnd	        0
 #define ZR36057_VFEHCR_Hmask	        0x3ff
 
-#define ZR36057_VFEVCR          0x004	/* Video Front End, Vertical Configuration Register */
+#define ZR36057_VFEVCR          0x004   /* Video Front End, Vertical Configuration Register */
 #define ZR36057_VFEVCR_VSPol            (1<<30)
 #define ZR36057_VFEVCR_VStart           10
 #define ZR36057_VFEVCR_VEnd	        0
 #define ZR36057_VFEVCR_Vmask	        0x3ff
 
-#define ZR36057_VFESPFR         0x008	/* Video Front End, Scaler and Pixel Format Register */
+#define ZR36057_VFESPFR         0x008   /* Video Front End, Scaler and Pixel Format Register */
 #define ZR36057_VFESPFR_ExtFl           (1<<26)
 #define ZR36057_VFESPFR_TopField        (1<<25)
 #define ZR36057_VFESPFR_VCLKPol         (1<<24)
@@ -52,65 +52,65 @@
 #define ZR36057_VFESPFR_Pack24          (1<<1)
 #define ZR36057_VFESPFR_LittleEndian    (1<<0)
 
-#define ZR36057_VDTR            0x00c	/* Video Display "Top" Register */
+#define ZR36057_VDTR            0x00c   /* Video Display "Top" Register */
 
-#define ZR36057_VDBR            0x010	/* Video Display "Bottom" Register */
+#define ZR36057_VDBR            0x010   /* Video Display "Bottom" Register */
 
-#define ZR36057_VSSFGR          0x014	/* Video Stride, Status, and Frame Grab Register */
+#define ZR36057_VSSFGR          0x014   /* Video Stride, Status, and Frame Grab Register */
 #define ZR36057_VSSFGR_DispStride       16
 #define ZR36057_VSSFGR_VidOvf           (1<<8)
 #define ZR36057_VSSFGR_SnapShot         (1<<1)
 #define ZR36057_VSSFGR_FrameGrab        (1<<0)
 
-#define ZR36057_VDCR            0x018	/* Video Display Configuration Register */
+#define ZR36057_VDCR            0x018   /* Video Display Configuration Register */
 #define ZR36057_VDCR_VidEn              (1<<31)
 #define ZR36057_VDCR_MinPix             24
 #define ZR36057_VDCR_Triton             (1<<24)
 #define ZR36057_VDCR_VidWinHt           12
 #define ZR36057_VDCR_VidWinWid          0
 
-#define ZR36057_MMTR            0x01c	/* Masking Map "Top" Register */
+#define ZR36057_MMTR            0x01c   /* Masking Map "Top" Register */
 
-#define ZR36057_MMBR            0x020	/* Masking Map "Bottom" Register */
+#define ZR36057_MMBR            0x020   /* Masking Map "Bottom" Register */
 
-#define ZR36057_OCR             0x024	/* Overlay Control Register */
+#define ZR36057_OCR             0x024   /* Overlay Control Register */
 #define ZR36057_OCR_OvlEnable           (1 << 15)
 #define ZR36057_OCR_MaskStride          0
 
-#define ZR36057_SPGPPCR         0x028	/* System, PCI, and General Purpose Pins Control Register */
+#define ZR36057_SPGPPCR         0x028   /* System, PCI, and General Purpose Pins Control Register */
 #define ZR36057_SPGPPCR_SoftReset	(1<<24)
 
-#define ZR36057_GPPGCR1         0x02c	/* General Purpose Pins and GuestBus Control Register (1) */
+#define ZR36057_GPPGCR1         0x02c   /* General Purpose Pins and GuestBus Control Register (1) */
 
-#define ZR36057_MCSAR           0x030	/* MPEG Code Source Address Register */
+#define ZR36057_MCSAR           0x030   /* MPEG Code Source Address Register */
 
-#define ZR36057_MCTCR           0x034	/* MPEG Code Transfer Control Register */
+#define ZR36057_MCTCR           0x034   /* MPEG Code Transfer Control Register */
 #define ZR36057_MCTCR_CodTime           (1 << 30)
 #define ZR36057_MCTCR_CEmpty            (1 << 29)
 #define ZR36057_MCTCR_CFlush            (1 << 28)
 #define ZR36057_MCTCR_CodGuestID	20
 #define ZR36057_MCTCR_CodGuestReg	16
 
-#define ZR36057_MCMPR           0x038	/* MPEG Code Memory Pointer Register */
+#define ZR36057_MCMPR           0x038   /* MPEG Code Memory Pointer Register */
 
-#define ZR36057_ISR             0x03c	/* Interrupt Status Register */
+#define ZR36057_ISR             0x03c   /* Interrupt Status Register */
 #define ZR36057_ISR_GIRQ1               (1<<30)
 #define ZR36057_ISR_GIRQ0               (1<<29)
 #define ZR36057_ISR_CodRepIRQ           (1<<28)
 #define ZR36057_ISR_JPEGRepIRQ          (1<<27)
 
-#define ZR36057_ICR             0x040	/* Interrupt Control Register */
+#define ZR36057_ICR             0x040   /* Interrupt Control Register */
 #define ZR36057_ICR_GIRQ1               (1<<30)
 #define ZR36057_ICR_GIRQ0               (1<<29)
 #define ZR36057_ICR_CodRepIRQ           (1<<28)
 #define ZR36057_ICR_JPEGRepIRQ          (1<<27)
 #define ZR36057_ICR_IntPinEn            (1<<24)
 
-#define ZR36057_I2CBR           0x044	/* I2C Bus Register */
+#define ZR36057_I2CBR           0x044   /* I2C Bus Register */
 #define ZR36057_I2CBR_SDA       	(1<<1)
 #define ZR36057_I2CBR_SCL       	(1<<0)
 
-#define ZR36057_JMC             0x100	/* JPEG Mode and Control */
+#define ZR36057_JMC             0x100   /* JPEG Mode and Control */
 #define ZR36057_JMC_JPG                 (1 << 31)
 #define ZR36057_JMC_JPGExpMode          (0 << 29)
 #define ZR36057_JMC_JPGCmpMode          (1 << 29)
@@ -124,45 +124,45 @@
 #define ZR36057_JMC_CFIFO_FB            (1 << 1)
 #define ZR36057_JMC_Stll_LitEndian      (1 << 0)
 
-#define ZR36057_JPC             0x104	/* JPEG Process Control */
+#define ZR36057_JPC             0x104   /* JPEG Process Control */
 #define ZR36057_JPC_P_Reset             (1 << 7)
 #define ZR36057_JPC_CodTrnsEn           (1 << 5)
 #define ZR36057_JPC_Active              (1 << 0)
 
-#define ZR36057_VSP             0x108	/* Vertical Sync Parameters */
+#define ZR36057_VSP             0x108   /* Vertical Sync Parameters */
 #define ZR36057_VSP_VsyncSize           16
 #define ZR36057_VSP_FrmTot              0
 
-#define ZR36057_HSP             0x10c	/* Horizontal Sync Parameters */
+#define ZR36057_HSP             0x10c   /* Horizontal Sync Parameters */
 #define ZR36057_HSP_HsyncStart          16
 #define ZR36057_HSP_LineTot             0
 
-#define ZR36057_FHAP            0x110	/* Field Horizontal Active Portion */
+#define ZR36057_FHAP            0x110   /* Field Horizontal Active Portion */
 #define ZR36057_FHAP_NAX                16
 #define ZR36057_FHAP_PAX                0
 
-#define ZR36057_FVAP            0x114	/* Field Vertical Active Portion */
+#define ZR36057_FVAP            0x114   /* Field Vertical Active Portion */
 #define ZR36057_FVAP_NAY                16
 #define ZR36057_FVAP_PAY                0
 
-#define ZR36057_FPP             0x118	/* Field Process Parameters */
+#define ZR36057_FPP             0x118   /* Field Process Parameters */
 #define ZR36057_FPP_Odd_Even            (1 << 0)
 
-#define ZR36057_JCBA            0x11c	/* JPEG Code Base Address */
+#define ZR36057_JCBA            0x11c   /* JPEG Code Base Address */
 
-#define ZR36057_JCFT            0x120	/* JPEG Code FIFO Threshold */
+#define ZR36057_JCFT            0x120   /* JPEG Code FIFO Threshold */
 
-#define ZR36057_JCGI            0x124	/* JPEG Codec Guest ID */
+#define ZR36057_JCGI            0x124   /* JPEG Codec Guest ID */
 #define ZR36057_JCGI_JPEGuestID         4
 #define ZR36057_JCGI_JPEGuestReg        0
 
-#define ZR36057_GCR2            0x12c	/* GuestBus Control Register (2) */
+#define ZR36057_GCR2            0x12c   /* GuestBus Control Register (2) */
 
-#define ZR36057_POR             0x200	/* Post Office Register */
+#define ZR36057_POR             0x200   /* Post Office Register */
 #define ZR36057_POR_POPen               (1<<25)
 #define ZR36057_POR_POTime              (1<<24)
 #define ZR36057_POR_PODir               (1<<23)
 
-#define ZR36057_STR             0x300	/* "Still" Transfer Register */
+#define ZR36057_STR             0x300   /* "Still" Transfer Register */
 
 #endif
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36060.h linux/drivers/media/video/zr36060.h
--- v2.4.6/linux/drivers/media/video/zr36060.h	Mon Jul  5 20:09:40 1999
+++ linux/drivers/media/video/zr36060.h	Wed Jul  4 14:41:33 2001
@@ -1,22 +1,22 @@
 /* 
-   zr36060.h - zr36060 register offsets
+    zr36060.h - zr36060 register offsets
 
-   Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.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 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.
+    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.
- */
+    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 _ZR36060_H_
 #define _ZR36060_H_
diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- v2.4.6/linux/drivers/media/video/zr36067.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/zr36067.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,4900 @@
+#define DEBUGLEVEL 0
+#define MAX_KMALLOC_MEM (128*1024)
+
+/*
+   Miro/Pinnacle Systems Inc. DC10/DC10plus and
+   Linux Media Labs LML33 video capture boards driver
+   now with IOMega BUZ support!
+   
+   Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+   Changes for BUZ by Wolfgang Scherr <scherr@net4you.net>
+   
+   Based on
+   
+    Miro DC10 driver
+    Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
+   
+    Iomega Buz driver version 1.0
+    Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+    buz.0.0.3
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    bttv - Bt848 frame grabber driver
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                           & Marcus Metzler (mocm@thp.uni-koeln.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.
+*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/i2c-old.h>
+#define     MAP_NR(x)       virt_to_page(x)
+#define     ZORAN_HARDWARE  VID_HARDWARE_ZR36067
+
+#include <linux/videodev.h>
+
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include "zoran.h"
+#include <linux/video_decoder.h>
+#include <linux/video_encoder.h>
+
+// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
+#if !defined(CONFIG_BIGPHYS_AREA)
+//#undef CONFIG_BIGPHYS_AREA
+#define BUZ_USE_HIMEM
+#endif
+
+#if defined(CONFIG_BIGPHYS_AREA)
+#   include <linux/bigphysarea.h>
+#endif
+
+#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | ZR36057_ISR_GIRQ1 | /* ZR36057_ISR_CodRepIRQ | */  ZR36057_ISR_JPEGRepIRQ )	// SW
+//#define GPIO_MASK 0xcd
+//#define GPIO_MASK 0x8d
+
+/*
+DC10:
+GPIO0 = /RESET ZR 36060
+GPIO1 = VIDEO BUS DIRECTION (0: CAPTURE, 1: DISPLAY)
+GPIO2 = VIDEO BUS ENABLE    (0: ON, 1: OFF)
+GPIO3 = /SLEEP ZR 36060
+GPIO4 = ADC7175 (video out) FREQUENCY (0: LCC/SAA7110, 1: 27 MHz (quarz))
+GPIO5 = ZORAN FREQUENCY  (0: LCC and LCC2 from SAA7110,
+                          1: 27 and 13.5 MHz (quarz))
+GPIO6 = /FRAME ZR 36060
+GPIO7 = /RESET ADV7175 (video out)
+(I think they lost the SAA7110 reset.....)
+
+GIRQ0 signals that ZR36060's DATERR# line is asserted.
+GIRQ1 signals a vertical sync of the video signal (VS SAA7110)
+
+  SAA7110A:
+   mode 0 - Composite
+   mode 1 - 
+   mode 2 - 
+   mode 3 - 
+   mode 4 - 
+   mode 5 - internal Composite (from PCTV)
+   mode 6 - 
+   mode 7 - S-Video
+
+BUZ:
+GPIO0 = 1, take board out of reset
+GPIO1 = 1, take JPEG codec out of sleep mode
+GPIO3 = 1, deassert FRAME# to 36060
+
+GIRQ0 signals a vertical sync of the video signal
+GIRQ1 signals that ZR36060's DATERR# line is asserted.
+
+SAA7111A
+
+   In their infinite wisdom, the Iomega engineers decided to
+   use the same input line for composite and S-Video Color,
+   although there are two entries not connected at all!
+   Through this ingenious strike, it is not possible to
+   keep two running video sources connected at the same time
+   to Composite and S-VHS input!
+
+   mode 0 - N/C
+   mode 1 - S-Video Y
+   mode 2 - noise or something I don't know
+   mode 3 - Composite and S-Video C
+   mode 4 - N/C
+   mode 5 - S-Video (gain C independently selectable of gain Y)
+   mode 6 - N/C
+   mode 7 - S-Video (gain C adapted to gain Y)
+*/
+
+#define MAJOR_VERSION 0		/* driver major version */
+#define MINOR_VERSION 7		/* driver minor version */
+
+#define ZORAN_NAME    "zr36067"	/* name of the device */
+
+#define BUZ_ERR       KERN_ERR     ZORAN_NAME
+#define BUZ_DEBUG     KERN_INFO    ZORAN_NAME
+#define BUZ_INFO      KERN_INFO    ZORAN_NAME
+#define BUZ_WARNING   KERN_WARNING ZORAN_NAME
+
+#if(DEBUGLEVEL>0)
+#define DEBUG1(x...)    x
+#else
+#define DEBUG1(x...)
+#endif
+
+#if(DEBUGLEVEL>1)
+#define DEBUG2(x...)    x
+#else
+#define DEBUG2(x...)
+#endif
+
+#if(DEBUGLEVEL>2)
+#define DEBUG3(x...)    x
+#else
+#define DEBUG3(x...)
+#endif
+
+#if(DEBUGLEVEL>3)
+#define DEBUG4(x...)    x
+#else
+#define DEBUG4(x...)
+#endif
+
+/* The parameters for this driver */
+
+/*
+   The video mem address of the video card.
+   The driver has a little database for some videocards
+   to determine it from there. If your video card is not in there
+   you have either to give it to the driver as a parameter
+   or set in in a VIDIOCSFBUF ioctl
+ */
+
+static unsigned long vidmem = 0;	/* Video memory base address */
+
+/* Special purposes only: */
+
+static int triton = 0;		/* 0=no, 1=yes */
+static int natoma = 0;		/* 0=no, 1=yes */
+
+/*
+   Number and size of grab buffers for Video 4 Linux
+   The vast majority of applications should not need more than 2,
+   the very popular BTTV driver actually does ONLY have 2.
+   Time sensitive applications might need more, the maximum
+   is VIDEO_MAX_FRAME (defined in <linux/videodev.h>).
+
+   The size is set so that the maximum possible request
+   can be satisfied. Decrease  it, if bigphys_area alloc'd
+   memory is low. If you don't have the bigphys_area patch,
+   set it to 128 KB. Will you allow only to grab small
+   images with V4L, but that's better than nothing.
+
+   v4l_bufsize has to be given in KB !
+
+*/
+
+static int v4l_nbufs = 2;
+static int v4l_bufsize = 128;	/* Everybody should be able to work with this setting */
+
+/*
+   Default input and video norm at startup of the driver.
+*/
+
+static int default_input = 0;	/* 0=Composite, 1=S-VHS */
+static int default_norm = 0;	/* 0=PAL, 1=NTSC 2=SECAM */
+static int lock_norm = 0;	/* 1=Don't change TV standard (norm) */
+
+static int pass_through = 0;	/* 1=Pass through TV signal when device is not used */
+				/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
+
+static int lml33dpath = 0;	/* 1 will use digital path in capture mode instead of analog.
+				   It can be used for picture adjustments using tool like xawtv
+				   while watching image on TV monitor connected to the output.
+				   However, due to absence of 75 Ohm load on Bt819 input, there
+				   will be some image imperfections */
+static int video_nr = -1;
+
+MODULE_PARM(vidmem, "i");
+MODULE_PARM(triton, "i");
+MODULE_PARM(natoma, "i");
+MODULE_PARM(v4l_nbufs, "i");
+MODULE_PARM(v4l_bufsize, "i");
+MODULE_PARM(default_input, "i");
+MODULE_PARM(default_norm, "i");
+MODULE_PARM(lock_norm, "i");
+MODULE_PARM(pass_through, "i");
+MODULE_PARM(lml33dpath, "i");
+MODULE_PARM(video_nr, "i");
+
+/* Anybody who uses more than four? */
+#define BUZ_MAX 4
+
+static int zoran_num;		/* number of Buzs in use */
+static struct zoran zoran[BUZ_MAX];
+
+/* forward references */
+
+static void v4l_fbuffer_free(struct zoran *zr);
+static void jpg_fbuffer_free(struct zoran *zr);
+static void zoran_feed_stat_com(struct zoran *zr);
+
+/*
+ *   Allocate the V4L grab buffers
+ *
+ *   These have to be pysically contiguous.
+ *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
+ *   else we try to allocate them with bigphysarea_alloc_pages
+ *   if the bigphysarea patch is present in the kernel,
+ *   else we try to use high memory (if the user has bootet
+ *   Linux with the necessary memory left over).
+ */
+
+static int v4l_fbuffer_alloc(struct zoran *zr)
+{
+	int i, off;
+	unsigned char *mem;
+
+	for (i = 0; i < v4l_nbufs; i++) {
+		if (zr->v4l_gbuf[i].fbuffer)
+			printk(KERN_WARNING
+			       "%s: v4l_fbuffer_alloc: buffer %d allready allocated ???\n",
+			       zr->name, i);
+
+		//udelay(20);
+		if (v4l_bufsize <= MAX_KMALLOC_MEM) {
+			/* Use kmalloc */
+
+			mem =
+			    (unsigned char *) kmalloc(v4l_bufsize,
+						      GFP_KERNEL);
+			if (mem == 0) {
+				printk(KERN_ERR
+				       "%s: kmalloc for V4L bufs failed\n",
+				       zr->name);
+				v4l_fbuffer_free(zr);
+				return -ENOBUFS;
+			}
+			zr->v4l_gbuf[i].fbuffer = mem;
+			zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
+			zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
+			for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
+				mem_map_reserve(MAP_NR(mem + off));
+			DEBUG1(printk
+			       (KERN_INFO
+				"%s: V4L frame %d mem 0x%lx (bus: 0x%lx)\n",
+				zr->name, i, (unsigned long) mem,
+				virt_to_bus(mem)));
+		} else {
+#if defined(CONFIG_BIGPHYS_AREA)
+			/* Use bigphysarea_alloc_pages */
+
+			int n = (v4l_bufsize + PAGE_SIZE - 1) / PAGE_SIZE;
+			mem =
+			    (unsigned char *) bigphysarea_alloc_pages(n, 0,
+								      GFP_KERNEL);
+			if (mem == 0) {
+				printk(KERN_ERR
+				       "%s: bigphysarea_alloc_pages for V4L bufs failed\n",
+				       zr->name);
+				v4l_fbuffer_free(zr);
+				return -ENOBUFS;
+			}
+			zr->v4l_gbuf[i].fbuffer = mem;
+			zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem);
+			zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem);
+			DEBUG1(printk
+			       (KERN_INFO
+				"%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
+				zr->name, i, (unsigned) mem,
+				(unsigned) virt_to_bus(mem)));
+
+			/* Zero out the allocated memory */
+			memset(zr->v4l_gbuf[i].fbuffer, 0, v4l_bufsize);
+#else
+			/* No bigphysarea present, usage of high memory disabled,
+			   but user wants buffers of more than MAX_KMALLOC_MEM */
+			printk(KERN_ERR
+			       "%s: No bigphysarea_patch present, usage of high memory disabled,\n",
+			       zr->name);
+			printk(KERN_ERR
+			       "%s: sorry, could not allocate V4L buffers of size %d KB.\n",
+			       zr->name, v4l_bufsize >> 10);
+			return -ENOBUFS;
+#endif
+		}
+	}
+
+	return 0;
+}
+
+/* free the V4L grab buffers */
+
+static void v4l_fbuffer_free(struct zoran *zr)
+{
+	int i, off;
+	unsigned char *mem;
+
+	for (i = 0; i < v4l_nbufs; i++) {
+		if (!zr->v4l_gbuf[i].fbuffer)
+			continue;
+
+		if (v4l_bufsize <= MAX_KMALLOC_MEM) {
+			mem = zr->v4l_gbuf[i].fbuffer;
+			for (off = 0; off < v4l_bufsize; off += PAGE_SIZE)
+				mem_map_unreserve(MAP_NR(mem + off));
+			kfree((void *) zr->v4l_gbuf[i].fbuffer);
+		}
+#if defined(CONFIG_BIGPHYS_AREA)
+		else
+			bigphysarea_free_pages((void *) zr->v4l_gbuf[i].
+					       fbuffer);
+#endif
+		zr->v4l_gbuf[i].fbuffer = NULL;
+	}
+}
+
+/*
+ *   Allocate the MJPEG grab buffers.
+ *
+ *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
+ *   kmalloc is used to request a physically contiguous area,
+ *   else we allocate the memory in framgents with get_free_page.
+ *
+ *   If a Natoma chipset is present and this is a revision 1 zr36057,
+ *   each MJPEG buffer needs to be physically contiguous.
+ *   (RJ: This statement is from Dave Perks' original driver,
+ *   I could never check it because I have a zr36067)
+ *   The driver cares about this because it reduces the buffer
+ *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
+ *
+ *   RJ: The contents grab buffers needs never be accessed in the driver.
+ *       Therefore there is no need to allocate them with vmalloc in order
+ *       to get a contiguous virtual memory space.
+ *       I don't understand why many other drivers first allocate them with
+ *       vmalloc (which uses internally also get_free_page, but delivers you
+ *       virtual addresses) and then again have to make a lot of efforts
+ *       to get the physical address.
+ *
+ */
+
+static int jpg_fbuffer_alloc(struct zoran *zr)
+{
+	int i, j, off;		//alloc_contig;
+	unsigned long mem;
+
+	/* Decide if we should alloc contiguous or fragmented memory */
+	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
+
+	//alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM);
+
+	for (i = 0; i < zr->jpg_nbufs; i++) {
+		if (zr->jpg_gbuf[i].frag_tab)
+			printk(KERN_WARNING
+			       "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n",
+			       zr->name, i);
+
+		/* Allocate fragment table for this buffer */
+
+		mem = get_free_page(GFP_KERNEL);
+		if (mem == 0) {
+			printk(KERN_ERR
+			       "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n",
+			       zr->name, i);
+			jpg_fbuffer_free(zr);
+			return -ENOBUFS;
+		}
+		memset((void *) mem, 0, PAGE_SIZE);
+		zr->jpg_gbuf[i].frag_tab = (u32 *) mem;
+		zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem);
+
+		//if (alloc_contig) {
+		if (zr->need_contiguous) {
+			mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL);
+			if (mem == 0) {
+				printk(KERN_ERR "%s: jpg_fbuffer_alloc: kmalloc failed for buffer %d\n",
+				       zr->name, i);
+				jpg_fbuffer_free(zr);
+				return -ENOBUFS;
+			}
+			zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem);
+			zr->jpg_gbuf[i].frag_tab[1] =
+			    ((zr->jpg_bufsize / 4) << 1) | 1;
+			for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE)
+				mem_map_reserve(MAP_NR(mem + off));
+		} else {
+			/* jpg_bufsize is allreay page aligned */
+			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) 
+			{
+				mem = get_free_page(GFP_KERNEL);
+				if (mem == 0) {
+					printk(KERN_ERR
+					       "%s: jpg_fbuffer_alloc: get_free_page failed for buffer %d\n",
+					       zr->name, i);
+					jpg_fbuffer_free(zr);
+					return -ENOBUFS;
+				}
+
+				zr->jpg_gbuf[i].frag_tab[2 * j] =
+				    virt_to_bus((void *) mem);
+				zr->jpg_gbuf[i].frag_tab[2 * j + 1] =
+				    (PAGE_SIZE / 4) << 1;
+				mem_map_reserve(MAP_NR(mem));
+			}
+
+			zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1;
+		}
+	}
+
+	DEBUG1(printk
+	       ("%s: jpg_fbuffer_alloc: %ld KB allocated\n", zr->name,
+		(zr->jpg_nbufs * zr->jpg_bufsize) >> 10));
+	zr->jpg_buffers_allocated = 1;
+	return 0;
+}
+
+/* free the MJPEG grab buffers */
+static void jpg_fbuffer_free(struct zoran *zr)
+{
+	int i, j, off;		// alloc_contig;
+	unsigned char *mem;
+
+	/* Decide if we should alloc contiguous or fragmented memory */
+	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
+
+	//alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM);
+
+	for (i = 0; i < zr->jpg_nbufs; i++) {
+		if (!zr->jpg_gbuf[i].frag_tab)
+			continue;
+
+		//if (alloc_contig) {
+		if (zr->need_contiguous) {
+			if (zr->jpg_gbuf[i].frag_tab[0]) {
+				mem =
+				    (unsigned char *) bus_to_virt(zr->
+								  jpg_gbuf
+								  [i].
+								  frag_tab
+								  [0]);
+				for (off = 0; off < zr->jpg_bufsize;
+				     off += PAGE_SIZE)
+					mem_map_unreserve(MAP_NR
+							  (mem + off));
+				kfree((void *) mem);
+				zr->jpg_gbuf[i].frag_tab[0] = 0;
+				zr->jpg_gbuf[i].frag_tab[1] = 0;
+			}
+		} else {
+			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+				if (!zr->jpg_gbuf[i].frag_tab[2 * j])
+					break;
+				mem_map_unreserve(MAP_NR
+						  (bus_to_virt
+						   (zr->jpg_gbuf[i].
+						    frag_tab[2 * j])));
+				free_page((unsigned long)
+					  bus_to_virt(zr->jpg_gbuf[i].
+						      frag_tab[2 * j]));
+				zr->jpg_gbuf[i].frag_tab[2 * j] = 0;
+				zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0;
+			}
+		}
+
+		free_page((unsigned long) zr->jpg_gbuf[i].frag_tab);
+		zr->jpg_gbuf[i].frag_tab = NULL;
+	}
+	zr->jpg_buffers_allocated = 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/* I2C functions                                                           */
+
+#define I2C_DELAY   10
+
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data)
+{
+	struct zoran *zr = (struct zoran *) bus->data;
+	btwrite((data << 1) | ctrl, ZR36057_I2CBR);
+	udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+	struct zoran *zr = (struct zoran *) bus->data;
+	return (btread(ZR36057_I2CBR) >> 1) & 1;
+}
+
+static void attach_inform(struct i2c_bus *bus, int id)
+{
+	int i;
+	struct zoran *zr = (struct zoran *) bus->data;
+
+	DEBUG1(printk(KERN_DEBUG "%s: i2c attach %02x\n", zr->name, id));
+	for (i = 0; i < bus->devcount; i++) {
+		if (strcmp(bus->devices[i]->name, "saa7110") == 0) {
+			if (zr->revision < 2) {
+				zr->card = DC10;
+				sprintf(zr->name, "DC10[%u]", zr->id);
+			} else {
+				zr->card = DC10plus;
+				sprintf(zr->name, "DC10plus[%u]", zr->id);
+			}
+			break;
+		}
+		if (strcmp(bus->devices[i]->name, "bt819") == 0) {
+			zr->card = LML33;
+			sprintf(zr->name, "LML33[%u]", zr->id);
+			break;
+		}
+		if (strcmp(bus->devices[i]->name, "saa7111") == 0) {
+			zr->card = BUZ;
+			sprintf(zr->name, "Buz[%u]", zr->id);
+			break;
+		}
+	}
+}
+
+static void detach_inform(struct i2c_bus *bus, int id)
+{
+	DEBUG1(struct zoran *zr = (struct zoran *) bus->data);
+	DEBUG1(printk(KERN_DEBUG "%s: i2c detach %02x\n", zr->name, id));
+}
+
+static struct i2c_bus zoran_i2c_bus_template = {
+	"zr36057",
+	I2C_BUSID_BT848,
+	NULL,
+
+	SPIN_LOCK_UNLOCKED,
+
+	attach_inform,
+	detach_inform,
+
+	i2c_setlines,
+	i2c_getdataline,
+	NULL,
+	NULL,
+};
+
+/*
+ *   Set the registers for the size we have specified. Don't bother
+ *   trying to understand this without the ZR36057 manual in front of
+ *   you [AC].
+ *
+ *   PS: The manual is free for download in .pdf format from
+ *   www.zoran.com - nicely done those folks.
+ */
+
+static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
+static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
+
+static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 };
+
+static struct tvnorm *dc10norms[] = {
+	&f50sqpixel,		/* PAL-BDGHI */
+	&f60sqpixel,		/* NTSC */
+	&f50sqpixel,		/* SECAM */
+};
+
+static struct tvnorm *lml33norms[] = {
+	&f50ccir601,		/* PAL-BDGHI */
+	&f60ccir601,		/* NTSC      */
+	NULL,			/* SECAM (not supported in LML33) */
+};
+
+static struct tvnorm *buznorms[] = {
+	&f50ccir601,		/* PAL-BDGHI */
+	&f60ccir601,		/* NTSC      */
+	NULL,			/* SECAM     */
+};
+
+static struct tvnorm *unsupported[] = {
+	NULL,			/* PAL-BDGHI */
+	NULL,			/* NTSC      */
+	NULL,			/* SECAM     */
+};
+
+static struct tvnorm **cardnorms[] = {
+	unsupported,		/* UNKNOWN  */
+	dc10norms,		/* DC10     */
+	dc10norms,		/* DC10plus */
+	lml33norms,		/* LML33    */
+	buznorms,		/* Buz      */
+};
+
+static u32 cardvsync[] = {
+	0,			/* UNKNOWN  */
+	ZR36057_ISR_GIRQ1,	/* DC10     */
+	ZR36057_ISR_GIRQ1,	/* DC10plus */
+	ZR36057_ISR_GIRQ0,	/* LML33    */
+	ZR36057_ISR_GIRQ0,	/* Buz      */
+};
+
+static u32 cardjpegint[] = {
+	0,			/* UNKNOWN  */
+	ZR36057_ISR_GIRQ0,	/* DC10     */
+	ZR36057_ISR_GIRQ0,	/* DC10plus */
+	ZR36057_ISR_GIRQ1,	/* LML33    */
+	ZR36057_ISR_GIRQ1,	/* Buz      */
+};
+
+static int format2bpp(int format)
+{
+	int bpp;
+
+	/* Determine the number of bytes per pixel for the video format requested */
+
+	switch (format) {
+
+	case VIDEO_PALETTE_YUV422:
+		bpp = 2;
+		break;
+
+	case VIDEO_PALETTE_RGB555:
+		bpp = 2;
+		break;
+
+	case VIDEO_PALETTE_RGB565:
+		bpp = 2;
+		break;
+
+	case VIDEO_PALETTE_RGB24:
+		bpp = 3;
+		break;
+
+	case VIDEO_PALETTE_RGB32:
+		bpp = 4;
+		break;
+
+	default:
+		bpp = 0;
+	}
+
+	return bpp;
+}
+
+static void zr36057_adjust_vfe(struct zoran *zr,
+			       enum zoran_codec_mode mode)
+{
+	u32 reg;
+	switch (mode) {
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		reg = btread(ZR36057_VFEHCR);
+		if (reg & (1 << 10)) {
+			reg += ((1 << 10) | 1);
+		}
+		btwrite(reg, ZR36057_VFEHCR);
+		break;
+	case BUZ_MODE_MOTION_COMPRESS:
+	case BUZ_MODE_IDLE:
+	default:
+		if (zr->params.norm == VIDEO_MODE_NTSC)
+			btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		else
+			btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR);
+		reg = btread(ZR36057_VFEHCR);
+		if (!(reg & (1 << 10))) {
+			reg -= ((1 << 10) | 1);
+		}
+		btwrite(reg, ZR36057_VFEHCR);
+		break;
+	}
+}
+
+/*
+ * set geometry
+ */
+static void zr36057_set_vfe(struct zoran *zr, int video_width,
+			    int video_height, unsigned int video_format)
+{
+	struct tvnorm *tvn;
+	unsigned HStart, HEnd, VStart, VEnd;
+	unsigned DispMode;
+	unsigned VidWinWid, VidWinHt;
+	unsigned hcrop1, hcrop2, vcrop1, vcrop2;
+	unsigned Wa, We, Ha, He;
+	unsigned X, Y, HorDcm, VerDcm;
+	u32 reg;
+	unsigned mask_line_size;
+
+	tvn = zr->timing;
+
+	Wa = tvn->Wa;
+	Ha = tvn->Ha;
+
+	DEBUG1(printk (BUZ_INFO ": width = %d, height = %d\n", video_width, video_height));
+
+	if (zr->params.norm != VIDEO_MODE_PAL
+	    && zr->params.norm != VIDEO_MODE_NTSC
+	    && zr->params.norm != VIDEO_MODE_SECAM) {
+		printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n",
+		       zr->name, zr->params.norm);
+		return;
+	}
+	if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT
+	    || video_width > Wa || video_height > Ha) {
+		printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n",
+		       zr->name, video_width, video_height);
+		return;
+	}
+
+	/* if window has more than half of active height,
+	   switch on interlacing - we want the full information */
+
+	zr->video_interlace = (video_height > Ha / 2);
+
+	/**** zr36057 ****/
+
+	/* horizontal */
+	VidWinWid = video_width;
+	X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa;
+	We = (VidWinWid * 64) / X;
+	HorDcm = 64 - X;
+	hcrop1 = 2 * ((tvn->Wa - We) / 4);
+	hcrop2 = tvn->Wa - We - hcrop1;
+	HStart = tvn->HStart | 1;
+	if (zr->card == LML33)
+		HStart += 62;
+	if (zr->card == BUZ) {	//HStart += 67;
+		HStart += 44;
+	}
+	HEnd = HStart + tvn->Wa - 1;
+	HStart += hcrop1;
+	HEnd -= hcrop2;
+	reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart)
+	    | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd);
+	if (zr->card != BUZ)
+		reg |= ZR36057_VFEHCR_HSPol;
+	btwrite(reg, ZR36057_VFEHCR);
+
+	/* Vertical */
+	DispMode = !zr->video_interlace;
+	VidWinHt = DispMode ? video_height : video_height / 2;
+	Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha;
+	He = (VidWinHt * 64) / Y;
+	VerDcm = 64 - Y;
+	vcrop1 = (tvn->Ha / 2 - He) / 2;
+	vcrop2 = tvn->Ha / 2 - He - vcrop1;
+	VStart = tvn->VStart;
+	VEnd = VStart + tvn->Ha / 2 - 1;
+	VStart += vcrop1;
+	VEnd -= vcrop2;
+	reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart)
+	    | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd);
+	reg |= ZR36057_VFEVCR_VSPol;
+	btwrite(reg, ZR36057_VFEVCR);
+
+	/* scaler and pixel format */
+	reg = 0;
+	reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
+	reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
+	reg |= (DispMode << ZR36057_VFESPFR_DispMode);
+	reg |= ZR36057_VFESPFR_LittleEndian;
+	/* RJ: I don't know, why the following has to be the opposite
+	   of the corresponding ZR36060 setting, but only this way
+	   we get the correct colors when uncompressing to the screen  */
+	//reg |= ZR36057_VFESPFR_VCLKPol; /**/
+	/* RJ: Don't know if that is needed for NTSC also */
+	if (zr->params.norm != VIDEO_MODE_NTSC)
+		reg |= ZR36057_VFESPFR_ExtFl;	// NEEDED!!!!!!! Wolfgang
+	reg |= ZR36057_VFESPFR_TopField;
+	switch (video_format) {
+
+	case VIDEO_PALETTE_YUV422:
+		reg |= ZR36057_VFESPFR_YUV422;
+		break;
+
+	case VIDEO_PALETTE_RGB555:
+		reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
+		break;
+
+	case VIDEO_PALETTE_RGB565:
+		reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
+		break;
+
+	case VIDEO_PALETTE_RGB24:
+		reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
+		break;
+
+	case VIDEO_PALETTE_RGB32:
+		reg |= ZR36057_VFESPFR_RGB888;
+		break;
+
+	default:
+		printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name,
+		       video_format);
+		return;
+
+	}
+	if (HorDcm >= 48) {
+		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
+	} else if (HorDcm >= 32) {
+		reg |= 2 << ZR36057_VFESPFR_HFilter;	/* 4 tap filter */
+	} else if (HorDcm >= 16) {
+		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
+	}
+	btwrite(reg, ZR36057_VFESPFR);
+
+	/* display configuration */
+
+	reg = (16 << ZR36057_VDCR_MinPix)
+	    | (VidWinHt << ZR36057_VDCR_VidWinHt)
+	    | (VidWinWid << ZR36057_VDCR_VidWinWid);
+	if (triton || zr->revision <= 1)
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+
+	/* Write overlay clipping mask data, but don't enable overlay clipping */
+	/* RJ: since this makes only sense on the screen, we use 
+	   zr->window.width instead of video_width */
+
+	mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+	reg = virt_to_bus(zr->overlay_mask);
+	btwrite(reg, ZR36057_MMTR);
+	reg = virt_to_bus(zr->overlay_mask + mask_line_size);
+	btwrite(reg, ZR36057_MMBR);
+	reg = mask_line_size - (zr->window.width + 31) / 32;
+	if (DispMode == 0)
+		reg += mask_line_size;
+	reg <<= ZR36057_OCR_MaskStride;
+	btwrite(reg, ZR36057_OCR);
+
+	zr36057_adjust_vfe(zr, zr->codec_mode);
+
+}
+
+/*
+ * Switch overlay on or off
+ */
+
+static void zr36057_overlay(struct zoran *zr, int on)
+{
+	int fmt, bpp;
+	u32 reg;
+
+	if (on) {
+		/* do the necessary settings ... */
+
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);	/* switch it off first */
+
+		switch (zr->buffer.depth) {
+		case 15:
+			fmt = VIDEO_PALETTE_RGB555;
+			bpp = 2;
+			break;
+		case 16:
+			fmt = VIDEO_PALETTE_RGB565;
+			bpp = 2;
+			break;
+		case 24:
+			fmt = VIDEO_PALETTE_RGB24;
+			bpp = 3;
+			break;
+		case 32:
+			fmt = VIDEO_PALETTE_RGB32;
+			bpp = 4;
+			break;
+		default:
+			fmt = 0;
+			bpp = 0;
+		}
+
+		zr36057_set_vfe(zr, zr->window.width, zr->window.height,
+				fmt);
+
+		/* Start and length of each line MUST be 4-byte aligned.
+		   This should be allready checked before the call to this routine.
+		   All error messages are internal driver checking only! */
+
+		/* video display top and bottom registers */
+
+		reg =
+		    (u32) zr->buffer.base + zr->window.x * bpp +
+		    zr->window.y * zr->buffer.bytesperline;
+		btwrite(reg, ZR36057_VDTR);
+		if (reg & 3)
+			printk(KERN_ERR
+			       "%s: zr36057_overlay: video_address not aligned\n",
+			       zr->name);
+		if (zr->video_interlace)
+			reg += zr->buffer.bytesperline;
+		btwrite(reg, ZR36057_VDBR);
+
+		/* video stride, status, and frame grab register */
+
+		reg = zr->buffer.bytesperline - zr->window.width * bpp;
+		if (zr->video_interlace)
+			reg += zr->buffer.bytesperline;
+		if (reg & 3)
+			printk(KERN_ERR
+			       "%s: zr36057_overlay: video_stride not aligned\n",
+			       zr->name);
+		reg = (reg << ZR36057_VSSFGR_DispStride);
+		reg |= ZR36057_VSSFGR_VidOvf;	/* clear overflow status */
+		btwrite(reg, ZR36057_VSSFGR);
+
+		/* Set overlay clipping */
+
+		if (zr->window.clipcount)
+			btor(ZR36057_OCR_OvlEnable, ZR36057_OCR);
+
+		/* ... and switch it on */
+
+		btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	} else {
+		/* Switch it off */
+
+		btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+	}
+}
+
+/*
+ * The overlay mask has one bit for each pixel on a scan line,
+ *  and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels.
+ */
+static void write_overlay_mask(struct zoran *zr, struct video_clip *vp,
+			       int count)
+{
+	unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
+	u32 *mask;
+	int x, y, width, height;
+	unsigned i, j, k;
+	u32 reg;
+
+	/* fill mask with one bits */
+	memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
+	reg = 0;
+
+	for (i = 0; i < count; ++i) {
+		/* pick up local copy of clip */
+		x = vp[i].x;
+		y = vp[i].y;
+		width = vp[i].width;
+		height = vp[i].height;
+
+		/* trim clips that extend beyond the window */
+		if (x < 0) {
+			width += x;
+			x = 0;
+		}
+		if (y < 0) {
+			height += y;
+			y = 0;
+		}
+		if (x + width > zr->window.width) {
+			width = zr->window.width - x;
+		}
+		if (y + height > zr->window.height) {
+			height = zr->window.height - y;
+		}
+
+		/* ignore degenerate clips */
+		if (height <= 0) {
+			continue;
+		}
+		if (width <= 0) {
+			continue;
+		}
+
+		/* apply clip for each scan line */
+		for (j = 0; j < height; ++j) {
+			/* reset bit for each pixel */
+			/* this can be optimized later if need be */
+			mask = zr->overlay_mask + (y + j) * mask_line_size;
+			for (k = 0; k < width; ++k) {
+				mask[(x + k) / 32] &=
+				    ~((u32) 1 << (x + k) % 32);
+			}
+		}
+	}
+}
+
+/* Enable/Disable uncompressed memory grabbing of the 36057 */
+
+static void zr36057_set_memgrab(struct zoran *zr, int mode)
+{
+	if (mode) {
+		if (btread(ZR36057_VSSFGR) &
+		    (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
+			printk(KERN_WARNING
+			       "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n",
+			       zr->name);
+
+		/* switch on VSync interrupts */
+
+		btwrite(IRQ_MASK, ZR36057_ISR);	// Clear Interrupts
+		btor(cardvsync[zr->card], ZR36057_ICR);	// SW
+
+		/* enable SnapShot */
+
+		btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+
+		/* Set zr36057 video front end  and enable video */
+
+		zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat);
+
+		zr->v4l_memgrab_active = 1;
+	} else {
+		zr->v4l_memgrab_active = 0;
+
+		/* switch off VSync interrupts */
+
+		//btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); // SW
+
+		/* reenable grabbing to screen if it was running */
+
+		if (zr->v4l_overlay_active) {
+			zr36057_overlay(zr, 1);
+		} else {
+			btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR);
+			btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR);
+		}
+	}
+}
+
+static int wait_grab_pending(struct zoran *zr)
+{
+	unsigned long flags;
+
+	/* wait until all pending grabs are finished */
+
+	if (!zr->v4l_memgrab_active)
+		return 0;
+
+	while (zr->v4l_pend_tail != zr->v4l_pend_head) {
+		interruptible_sleep_on(&zr->v4l_capq);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	spin_lock_irqsave(&zr->lock, flags);
+	zr36057_set_memgrab(zr, 0);
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return 0;
+}
+
+/*
+ *   V4L Buffer grabbing
+ */
+
+static int v4l_grab(struct zoran *zr, struct video_mmap *mp)
+{
+	unsigned long flags;
+	int res, bpp;
+
+	/*
+	 * There is a long list of limitations to what is allowed to be grabbed
+	 * We don't output error messages here, since some programs (e.g. xawtv)
+	 * just try several settings to find out what is valid or not.
+	 */
+
+	/* No grabbing outside the buffer range! */
+
+	if (mp->frame >= v4l_nbufs || mp->frame < 0) {
+		DEBUG2(printk
+		       (KERN_ERR "%s: Can not grab frame %d\n", zr->name,
+			mp->frame));
+		return -EINVAL;
+	}
+
+	/* Check size and format of the grab wanted */
+
+	if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH
+	    || mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) {
+		DEBUG2(printk
+		       (KERN_ERR "%s: Wrong frame size.\n", zr->name));
+		return -EINVAL;
+	}
+
+	bpp = format2bpp(mp->format);
+	if (bpp == 0) {
+		DEBUG2(printk
+		       (KERN_ERR "%s: Wrong bytes-per-pixel format\n",
+			zr->name));
+		return -EINVAL;
+	}
+
+	/* Check against available buffer size */
+
+	if (mp->height * mp->width * bpp > v4l_bufsize) {
+		DEBUG2(printk
+		       (KERN_ERR "%s: Video buffer size is too small\n",
+			zr->name));
+		return -EINVAL;
+	}
+
+	/* The video front end needs 4-byte alinged line sizes */
+
+	if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) {
+		DEBUG2(printk
+		       (KERN_ERR "%s: Wrong frame alingment\n", zr->name));
+		return -EINVAL;
+	}
+
+	/*
+	 * To minimize the time spent in the IRQ routine, we avoid setting up
+	 * the video front end there.
+	 * If this grab has different parameters from a running streaming capture
+	 * we stop the streaming capture and start it over again.
+	 */
+
+	if (zr->v4l_memgrab_active
+	    && (zr->gwidth != mp->width || zr->gheight != mp->height
+		|| zr->gformat != mp->format)) {
+		res = wait_grab_pending(zr);
+		if (res)
+			return res;
+	}
+	zr->gwidth = mp->width;
+	zr->gheight = mp->height;
+	zr->gformat = mp->format;
+	zr->gbpl = bpp * zr->gwidth;
+
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	/* make sure a grab isn't going on currently with this buffer */
+
+	switch (zr->v4l_gbuf[mp->frame].state) {
+
+	default:
+	case BUZ_STATE_PEND:
+		res = -EBUSY;	/* what are you doing? */
+		break;
+
+	case BUZ_STATE_USER:
+	case BUZ_STATE_DONE:
+		/* since there is at least one unused buffer there's room for at least one more pend[] entry */
+		zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] =
+		    mp->frame;
+		zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND;
+		res = 0;
+		break;
+
+	}
+
+	/* put the 36057 into frame grabbing mode */
+
+	if (!res && !zr->v4l_memgrab_active)
+		zr36057_set_memgrab(zr, 1);
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+	//DEBUG2(printk(KERN_INFO "%s: Frame grab 3...\n", zr->name));
+
+	return res;
+}
+
+/*
+ * Sync on a V4L buffer
+ */
+
+static int v4l_sync(struct zoran *zr, int frame)
+{
+	unsigned long flags;
+
+	/* check passed-in frame number */
+
+	if (frame >= v4l_nbufs || frame < 0) {
+		DEBUG1(printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n",
+		       zr->name, frame));
+		return -EINVAL;
+	}
+
+	/* Check if is buffer was queued at all */
+
+	if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) {
+		DEBUG1(printk(KERN_ERR
+		       "%s: v4l_sync: Attempt to sync on a buffer which was not queued?\n",
+		       zr->name));
+		return -EPROTO;
+	}
+
+	/* wait on this buffer to get ready */
+
+	while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) {
+		interruptible_sleep_on(&zr->v4l_capq);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	/* buffer should now be in BUZ_STATE_DONE */
+
+	if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE)
+		printk(KERN_ERR "%s: v4l_sync - internal error\n",
+		       zr->name);
+
+	/* Check if streaming capture has finished */
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	if (zr->v4l_pend_tail == zr->v4l_pend_head)
+		zr36057_set_memgrab(zr, 0);
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *                                                                           *
+ *  Set up the Buz-specific MJPEG part                                       *
+ *                                                                           *
+ *****************************************************************************/
+
+/*
+Wait til post office is no longer busy */
+static int post_office_wait(struct zoran *zr)
+{
+	u32 por;
+
+//      while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) {
+	while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) {
+		/* wait for something to happen */
+	}
+	if ((por & ZR36057_POR_POTime) && zr->card != LML33
+	    && zr->card != BUZ) {
+		/* In LML33/BUZ \GWS line is not connected, so it has always timeout set */
+		printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por);
+		return -1;
+	}
+	return 0;
+}
+
+static int post_office_write(struct zoran *zr, unsigned guest,
+			     unsigned reg, unsigned value)
+{
+	u32 por;
+
+	por =
+	    ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) |
+	    ((reg & 7) << 16) | (value & 0xFF);
+	btwrite(por, ZR36057_POR);
+	return post_office_wait(zr);
+}
+
+static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg)
+{
+	u32 por;
+
+	por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16);
+	btwrite(por, ZR36057_POR);
+	if (post_office_wait(zr) < 0) {
+		return -1;
+	}
+	return btread(ZR36057_POR) & 0xFF;
+}
+
+static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg)) {
+		return -1;
+	}
+	return post_office_write(zr, 0, 3, val);
+}
+
+static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (zr36060_write_8(zr, reg + 0, val >> 8)) {
+		return -1;
+	}
+	return zr36060_write_8(zr, reg + 1, val >> 0);
+}
+
+static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (zr36060_write_8(zr, reg + 0, val >> 16)) {
+		return -1;
+	}
+	return zr36060_write_16(zr, reg + 1, val >> 0);
+}
+
+static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val)
+{
+	if (zr36060_write_16(zr, reg + 0, val >> 16)) {
+		return -1;
+	}
+	return zr36060_write_16(zr, reg + 2, val >> 0);
+}
+
+static u32 zr36060_read_8(struct zoran *zr, unsigned reg)
+{
+	if (post_office_wait(zr)
+	    || post_office_write(zr, 0, 1, reg >> 8)
+	    || post_office_write(zr, 0, 2, reg)) {
+		return -1;
+	}
+	return post_office_read(zr, 0, 3) & 0xFF;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void GPIO(struct zoran *zr, unsigned bit, unsigned value)
+{
+	u32 reg;
+	u32 mask;
+
+	mask = 1 << (24 + bit);
+	reg = btread(ZR36057_GPPGCR1) & ~mask;
+	if (value) {
+		reg |= mask;
+	}
+	btwrite(reg, ZR36057_GPPGCR1);
+	udelay(1);
+}
+
+
+static void zr36060_sleep(struct zoran *zr, int sleep)
+{
+	switch (zr->card) {
+	case DC10:
+	case DC10plus:
+		GPIO(zr, 3, !sleep);
+		break;
+	case BUZ:
+	case LML33:
+		GPIO(zr, 1, !sleep);
+		break;
+	default:
+		break;
+	}
+	if (!sleep)
+		udelay(500);
+	else
+		udelay(2);
+}
+
+static int zr36060_reset(struct zoran *zr)
+{
+	switch (zr->card) {
+	case DC10:
+	case DC10plus:
+		zr36060_sleep(zr, 0);
+		GPIO(zr, 0, 0);
+		udelay(2);
+		GPIO(zr, 0, 1);
+		udelay(2);
+		break;
+	case LML33:
+	case BUZ:
+		zr36060_sleep(zr, 0);
+		post_office_write(zr, 3, 0, 0);
+		udelay(2);
+	default:
+	}
+	return 0;
+}
+
+static void set_frame(struct zoran *zr, int val)
+{
+	switch (zr->card) {
+	case DC10:
+	case DC10plus:
+		GPIO(zr, 6, val);
+		break;
+	case LML33:
+	case BUZ:
+		GPIO(zr, 3, val);
+		break;
+	default:
+		break;
+	}
+}
+
+static void set_videobus_dir(struct zoran *zr, int val)
+{
+	switch (zr->card) {
+	case DC10:
+	case DC10plus:
+		GPIO(zr, 1, val);
+		break;
+	case LML33:
+		if (lml33dpath == 0)
+			GPIO(zr, 5, val);
+		else
+			GPIO(zr, 5, 1);
+		break;
+	case BUZ:
+	default:
+		break;
+	}
+}
+
+static void set_videobus_enable(struct zoran *zr, int val)
+{
+	switch (zr->card) {
+	case LML33:
+		GPIO(zr, 7, val);
+		break;
+	case DC10:
+	case DC10plus:
+	case BUZ:
+	default:
+		break;
+	}
+}
+
+static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+	int size, blocks;
+
+	reg = (1 << 0)		/* CodeMstr */
+	    |(0 << 2)		/* CFIS=0 */
+	    |(0 << 6)		/* Endian=0 */
+	    |(0 << 7);		/* Code16=0 */
+	zr36060_write_8(zr, 0x002, reg);
+
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+	case BUZ_MODE_STILL_DECOMPRESS:
+		reg = 0x00;	/* Codec mode = decompression */
+		break;
+
+	case BUZ_MODE_MOTION_COMPRESS:
+	case BUZ_MODE_STILL_COMPRESS:
+	default:
+		reg = 0xa4;	/* Codec mode = compression with variable scale factor */
+		break;
+
+	}
+	zr36060_write_8(zr, 0x003, reg);
+
+	reg = 0x00;		/* reserved, mbz */
+	zr36060_write_8(zr, 0x004, reg);
+
+	/* code volume */
+
+	/* Target field size in pixels: */
+	tvn = zr->timing;
+	size =
+	    (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) /
+	    (zr->params.VerDcm);
+	blocks = size / 64;
+
+	/* Target compressed field size in bits: */
+	size = size * 16;	/* uncompressed size in bits */
+	size = size * zr->params.quality / 400;	/* quality = 100 is a compression ratio 1:4 */
+
+	/* Lower limit (arbitrary, 1 KB) */
+	if (size < 8192)
+		size = 8192;
+
+	/* Upper limit: 6/8 of the code buffers */
+	if (size * zr->params.field_per_buff > zr->jpg_bufsize * 6)
+		size = zr->jpg_bufsize * 6 / zr->params.field_per_buff;
+
+	reg = size * 4 / blocks;
+	if (reg > 0xf0)
+		reg = 0xf0;	/* 480 bits/block, does 0xff represents unlimited? */
+	zr36060_write_8(zr, 0x005, reg);
+
+	/* JPEG markers */
+	reg = (zr->params.jpeg_markers) & 0x38;	/* DRI, DQT, DHT */
+	if (zr->params.COM_len)
+		reg |= JPEG_MARKER_COM;
+	if (zr->params.APP_len)
+		reg |= JPEG_MARKER_APP;
+	zr36060_write_8(zr, 0x006, reg);
+
+	if (zr->card != LML33 && zr->card != BUZ) {
+		reg = (0 << 3)	/* EOAV=0 */
+		    |(0 << 2)	/* EOI=0 */
+		    |(0 << 1)	/* END=0 */
+		    |(1 << 0);	/* DATERR=1 */
+	} else {
+		reg = (0 << 3)	/* EOAV=0 */
+		    |(0 << 2)	/* EOI=0 */
+		    |(0 << 1)	/* END=0 */
+		    |(0 << 0);	/* DATERR=0 */
+	}
+	zr36060_write_8(zr, 0x007, reg);
+
+	reg = size;
+	zr36060_write_32(zr, 0x009, reg);
+
+	reg = (size * 10) / 11;
+	zr36060_write_32(zr, 0x00d, reg);	// Not needed for compr. with variable scale factor, just in case ...
+
+	/* how do we set initial SF as a function of quality parameter? */
+	reg = 0x0100;		/* SF=1.0 */
+	zr36060_write_16(zr, 0x011, reg);
+
+	reg = 0x00ffffff;	/* AF=max */
+	zr36060_write_24(zr, 0x013, reg);
+
+	reg = 0x0000;		/* test */
+	zr36060_write_16(zr, 0x024, reg);
+
+	//post_office_read(zr,1,0);
+}
+
+static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+	unsigned HStart;
+
+	tvn = zr->timing;
+
+	reg = (0 << 7)		/* Video8     */
+	    |(0 << 6)		/* Range      */
+	    |(0 << 3)		/* FlDet      */
+	    |(1 << 2)		/* FlVedge    */
+	    |(0 << 1)		/* FlExt      */
+	    |(0 << 0);		/* SyncMstr   */
+
+	if (mode != BUZ_MODE_STILL_DECOMPRESS) {
+		/* limit pixels to range 16..235 as per CCIR-601 */
+		reg |= (1 << 6);	/* Range=1 */
+	}
+	zr36060_write_8(zr, 0x030, reg);
+
+	switch (zr->card) {
+	case DC10:
+	case DC10plus:
+		reg = (0 << 7)	/* VCLKPol   */
+		    |(0 << 6)	/* PValPol   */
+		    |(0 << 5)	/* PoePol    */
+		    |(0 << 4)	/* SImgPol   */
+		    |(1 << 3)	/* BLPol     */
+		    |(1 << 2)	/* FlPol     */
+		    |(1 << 1)	/* HSPol     */
+		    |(1 << 0);	/* VSPol     */
+		break;
+	case LML33:
+		reg = (0 << 7)	/* VCLKPol=0 */
+		    |(0 << 6)	/* PValPol=0 */
+		    |(1 << 5)	/* PoePol=1 */
+		    |(0 << 4)	/* SImgPol=0 */
+		    |(0 << 3)	/* BLPol=0 */
+		    |(0 << 2)	/* FlPol=0 */
+		    |(0 << 1)	/* HSPol=0, sync on falling edge */
+		    |(1 << 0);	/* VSPol=1 */
+		break;
+	case BUZ:
+	default:
+		reg = (0 << 7)	/* VCLKPol=0 */
+		    |(0 << 6)	/* PValPol=0 */
+		    |(1 << 5)	/* PoePol=1 */
+		    |(0 << 4)	/* SImgPol=0 */
+		    |(0 << 3)	/* BLPol=0 */
+		    |(0 << 2)	/* FlPol=0 */
+		    |(1 << 1)	/* HSPol=0, sync on falling edge */
+		    |(1 << 0);	/* VSPol=1 */
+		break;
+	}
+	zr36060_write_8(zr, 0x031, reg);
+
+	switch (zr->params.HorDcm) {
+	default:
+	case 1:
+		reg = (0 << 0);
+		break;		/* HScale = 0 */
+
+	case 2:
+		reg = (1 << 0);
+		break;		/* HScale = 1 */
+
+	case 4:
+		reg = (2 << 0);
+		break;		/* HScale = 2 */
+	}
+	if (zr->params.VerDcm == 2)
+		reg |= (1 << 2);
+	zr36060_write_8(zr, 0x032, reg);
+
+	reg = 0x00;		/* BackY */
+	zr36060_write_8(zr, 0x033, reg);
+
+	reg = 0x80;		/* BackU */
+	zr36060_write_8(zr, 0x034, reg);
+
+	reg = 0x80;		/* BackV */
+	zr36060_write_8(zr, 0x035, reg);
+
+	/* sync generator */
+
+	reg = tvn->Ht - 1;	/* Vtotal */
+	zr36060_write_16(zr, 0x036, reg);
+
+	reg = tvn->Wt - 1;	/* Htotal */
+	zr36060_write_16(zr, 0x038, reg);
+
+	reg = 6 - 1;		/* VsyncSize */
+	zr36060_write_8(zr, 0x03a, reg);
+
+	//reg   = 30 - 1;               /* HsyncSize */
+	reg = (zr->params.norm == 1 ? 57 : 68);
+	zr36060_write_8(zr, 0x03b, reg);
+
+	reg = tvn->VStart - 1;	/* BVstart */
+	zr36060_write_8(zr, 0x03c, reg);
+
+	reg += tvn->Ha / 2;	/* BVend */
+	zr36060_write_16(zr, 0x03e, reg);
+
+	reg = tvn->HStart + 64 - 1;	/* BHstart */
+	zr36060_write_8(zr, 0x03d, reg);
+
+	reg += tvn->Wa;		/* BHend */
+	zr36060_write_16(zr, 0x040, reg);
+
+	/* active area */
+	reg = zr->params.img_y + tvn->VStart;	/* Vstart */
+	zr36060_write_16(zr, 0x042, reg);
+
+	reg += zr->params.img_height;	/* Vend */
+	zr36060_write_16(zr, 0x044, reg);
+
+	HStart = tvn->HStart;
+	if (zr->card == BUZ) {
+		HStart += 44;
+	} else {
+		HStart += 64;
+	}
+	reg = zr->params.img_x + HStart;	/* Hstart */
+	zr36060_write_16(zr, 0x046, reg);
+
+	reg += zr->params.img_width;	/* Hend */
+	zr36060_write_16(zr, 0x048, reg);
+
+	/* subimage area */
+	reg = tvn->VStart - 4;	/* SVstart */
+	zr36060_write_16(zr, 0x04a, reg);
+
+	reg += tvn->Ha / 2 + 8;	/* SVend */
+	zr36060_write_16(zr, 0x04c, reg);
+
+	reg = tvn->HStart + 64 - 4;	/* SHstart */
+	zr36060_write_16(zr, 0x04e, reg);
+
+	reg += tvn->Wa + 8;	/* SHend */
+	zr36060_write_16(zr, 0x050, reg);
+}
+
+static void zr36060_set_jpg_SOF(struct zoran *zr)
+{
+	u32 reg;
+
+
+	reg = 0xffc0;		/* SOF marker */
+	zr36060_write_16(zr, 0x060, reg);
+
+	reg = 17;		/* SOF length */
+	zr36060_write_16(zr, 0x062, reg);
+
+	reg = 8;		/* precision 8 bits */
+	zr36060_write_8(zr, 0x064, reg);
+
+	reg = zr->params.img_height / zr->params.VerDcm;	/* image height */
+	zr36060_write_16(zr, 0x065, reg);
+
+	reg = zr->params.img_width / zr->params.HorDcm;	/* image width */
+	zr36060_write_16(zr, 0x067, reg);
+
+	reg = 3;		/* 3 color components */
+	zr36060_write_8(zr, 0x069, reg);
+
+	reg = 0x002100;		/* Y component */
+	zr36060_write_24(zr, 0x06a, reg);
+
+	reg = 0x011101;		/* U component */
+	zr36060_write_24(zr, 0x06d, reg);
+
+	reg = 0x021101;		/* V component */
+	zr36060_write_24(zr, 0x070, reg);
+}
+
+static void zr36060_set_jpg_SOS(struct zoran *zr)
+{
+	u32 reg;
+
+
+	reg = 0xffda;		/* SOS marker */
+	zr36060_write_16(zr, 0x07a, reg);
+
+	reg = 12;		/* SOS length */
+	zr36060_write_16(zr, 0x07c, reg);
+
+	reg = 3;		/* 3 color components */
+	zr36060_write_8(zr, 0x07e, reg);
+
+	reg = 0x0000;		/* Y component */
+	zr36060_write_16(zr, 0x07f, reg);
+
+	reg = 0x0111;		/* U component */
+	zr36060_write_16(zr, 0x081, reg);
+
+	reg = 0x0211;		/* V component */
+	zr36060_write_16(zr, 0x083, reg);
+
+	reg = 0x003f00;		/* Start, end spectral scans */
+	zr36060_write_24(zr, 0x085, reg);
+}
+
+static void zr36060_set_jpg_DRI(struct zoran *zr)
+{
+	u32 reg;
+
+
+	reg = 0xffdd;		/* DRI marker */
+	zr36060_write_16(zr, 0x0c0, reg);
+
+	reg = 4;		/* DRI length */
+	zr36060_write_16(zr, 0x0c2, reg);
+
+	reg = 8;		/* length in MCUs */
+	zr36060_write_16(zr, 0x0c4, reg);
+}
+
+static void zr36060_set_jpg_DQT(struct zoran *zr)
+{
+	unsigned i;
+	unsigned adr;
+	static const u8 dqt[] = {
+		0xff, 0xdb,	/* DHT marker */
+		0x00, 0x84,	/* DHT length */
+		0x00,		/* table ID 0 */
+		0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+		0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+		0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+		0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+		0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+		0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+		0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+		0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+		0x01,		/* table ID 1 */
+		0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+		0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+	};
+
+	/* write fixed quantitization tables */
+	adr = 0x0cc;
+	for (i = 0; i < sizeof(dqt); ++i) {
+		zr36060_write_8(zr, adr++, dqt[i]);
+	}
+}
+
+static void zr36060_set_jpg_DHT(struct zoran *zr)
+{
+	unsigned i;
+	unsigned adr;
+	static const u8 dht[] = {
+		0xff, 0xc4,	/* DHT marker */
+		0x01, 0xa2,	/* DHT length */
+		0x00,		/* table class 0, ID 0 */
+		0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,	/* # codes of length 1..8 */
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* # codes of length 8..16 */
+		0x00,		/* values for codes of length 2 */
+		0x01, 0x02, 0x03, 0x04, 0x05,	/* values for codes of length 3 */
+		0x06,		/* values for codes of length 4 */
+		0x07,		/* values for codes of length 5 */
+		0x08,		/* values for codes of length 6 */
+		0x09,		/* values for codes of length 7 */
+		0x0a,		/* values for codes of length 8 */
+		0x0b,		/* values for codes of length 9 */
+		0x01,		/* table class 0, ID 1 */
+		0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,	/* # codes of length 1..8 */
+		0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,	/* # codes of length 9..16 */
+		0x00, 0x01, 0x02,	/* values for codes of length 2 */
+		0x03,		/* values for codes of length 3 */
+		0x04,		/* values for codes of length 4 */
+		0x05,		/* values for codes of length 5 */
+		0x06,		/* values for codes of length 6 */
+		0x07,		/* values for codes of length 7 */
+		0x08,		/* values for codes of length 8 */
+		0x09,		/* values for codes of length 9 */
+		0x0a,		/* values for codes of length 10 */
+		0x0b,		/* values for codes of length 11 */
+		0x10,
+		0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+		0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+		0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+		0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+		0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+		0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+		0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+		0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+		0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+		0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+		0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+		0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+		0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+		0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+		0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+		0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+		0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+		0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+		0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+		0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+		0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+		0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+		0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+		0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
+		0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
+		0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+		0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,
+		0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23,
+		0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a,
+		0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
+		0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35,
+		0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+		0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55,
+		0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+		0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
+		0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84,
+		0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+		0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
+		0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+		0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+		0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+		0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+		0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+	};
+
+	/* write fixed Huffman tables */
+	adr = 0x1d4;
+	for (i = 0; i < sizeof(dht); ++i) {
+		zr36060_write_8(zr, adr++, dht[i]);
+	}
+}
+
+static void zr36060_set_jpg_APP(struct zoran *zr)
+{
+	unsigned adr;
+	int len, i;
+	u32 reg;
+
+
+	len = zr->params.APP_len;
+	if (len < 0)
+		len = 0;
+	if (len > 60)
+		len = 60;
+
+	i = zr->params.APPn;
+	if (i < 0)
+		i = 0;
+	if (i > 15)
+		i = 15;
+
+	reg = 0xffe0 + i;	/* APPn marker */
+	zr36060_write_16(zr, 0x380, reg);
+
+	reg = len + 2;		/* APPn len */
+	zr36060_write_16(zr, 0x382, reg);
+
+	/* write APPn data */
+	adr = 0x384;
+	for (i = 0; i < 60; i++) {
+		zr36060_write_8(zr, adr++,
+				(i < len ? zr->params.APP_data[i] : 0));
+	}
+}
+
+static void zr36060_set_jpg_COM(struct zoran *zr)
+{
+	unsigned adr;
+	int len, i;
+	u32 reg;
+
+
+	len = zr->params.COM_len;
+	if (len < 0)
+		len = 0;
+	if (len > 60)
+		len = 60;
+
+	reg = 0xfffe;		/* COM marker */
+	zr36060_write_16(zr, 0x3c0, reg);
+
+	reg = len + 2;		/* COM len */
+	zr36060_write_16(zr, 0x3c2, reg);
+
+	/* write COM data */
+	adr = 0x3c4;
+	for (i = 0; i < 60; i++) {
+		zr36060_write_8(zr, adr++,
+				(i < len ? zr->params.COM_data[i] : 0));
+	}
+}
+
+static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	unsigned i;
+	u32 reg;
+
+	zr36060_reset(zr);
+	mdelay(10);
+
+	reg = (0 << 7)		/* Load=0 */
+	    |(1 << 0);		/* SynRst=1 */
+	zr36060_write_8(zr, 0x000, reg);
+
+	zr36060_set_jpg(zr, mode);
+	zr36060_set_video(zr, mode);
+	zr36060_set_jpg_SOF(zr);
+	zr36060_set_jpg_SOS(zr);
+	zr36060_set_jpg_DRI(zr);
+	zr36060_set_jpg_DQT(zr);
+	zr36060_set_jpg_DHT(zr);
+	zr36060_set_jpg_APP(zr);
+	zr36060_set_jpg_COM(zr);
+
+	reg = (1 << 7)		/* Load=1 */
+	    |(1 << 0);		/* SynRst=0 */
+	zr36060_write_8(zr, 0x000, reg);
+
+	/* wait for codec to unbusy */
+	for (i = 0; i < 100000; ++i) {
+		reg = zr36060_read_8(zr, 0x001);
+		if ((reg & (1 << 7)) == 0) {
+			return;
+		}
+		//udelay(100);
+	}
+	printk(KERN_ERR "%sZR36060: stuck busy, statux=%02x\n", zr->name,
+	       reg);
+}
+
+static void init_jpeg_queue(struct zoran *zr)
+{
+	int i;
+	/* re-initialize DMA ring stuff */
+	zr->jpg_que_head = 0;
+	zr->jpg_dma_head = 0;
+	zr->jpg_dma_tail = 0;
+	zr->jpg_que_tail = 0;
+	zr->jpg_seq_num = 0;
+	zr->JPEG_error = 0;
+	zr->num_errors = 0;
+	zr->jpg_err_seq = 0;
+	zr->jpg_err_shift = 0;
+	zr->jpg_queued_num = 0;
+	for (i = 0; i < zr->jpg_nbufs; i++) {
+		zr->jpg_gbuf[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+	for (i = 0; i < BUZ_NUM_STAT_COM; i++) {
+		zr->stat_com[i] = 1;	/* mark as unavailable to zr36057 */
+	}
+}
+
+static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode)
+{
+	struct tvnorm *tvn;
+	u32 reg;
+
+	tvn = zr->timing;
+
+	/* assert P_Reset */
+	btwrite(0, ZR36057_JPC);
+
+	/* MJPEG compression mode */
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS:
+	default:
+		reg = ZR36057_JMC_MJPGCmpMode;
+		break;
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = ZR36057_JMC_MJPGExpMode;
+		reg |= ZR36057_JMC_SyncMstr;
+		/* RJ: The following is experimental - improves the output to screen */
+		//if(zr->params.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM
+		break;
+
+	case BUZ_MODE_STILL_COMPRESS:
+		reg = ZR36057_JMC_JPGCmpMode;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+		reg = ZR36057_JMC_JPGExpMode;
+		break;
+
+	}
+	reg |= ZR36057_JMC_JPG;
+	if (zr->params.field_per_buff == 1)
+		reg |= ZR36057_JMC_Fld_per_buff;
+	btwrite(reg, ZR36057_JMC);
+
+	/* vertical */
+	btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR);
+	reg =
+	    (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot);
+	btwrite(reg, ZR36057_VSP);
+	reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY)
+	    | (zr->params.img_height << ZR36057_FVAP_PAY);
+	btwrite(reg, ZR36057_FVAP);
+
+	/* horizontal */
+	btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
+	reg =
+	    ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) | (tvn->
+							     Wt <<
+							     ZR36057_HSP_LineTot);
+	btwrite(reg, ZR36057_HSP);
+	reg = ((zr->params.img_x + tvn->HStart + 4) << ZR36057_FHAP_NAX)
+	    | (zr->params.img_width << ZR36057_FHAP_PAX);
+	btwrite(reg, ZR36057_FHAP);
+
+	/* field process parameters */
+	if (zr->params.odd_even)
+		reg = ZR36057_FPP_Odd_Even;
+	else
+		reg = 0;
+	if (mode == BUZ_MODE_MOTION_DECOMPRESS && zr->card != LML33
+	    && zr->card != BUZ)
+		reg ^= ZR36057_FPP_Odd_Even;
+
+	btwrite(reg, ZR36057_FPP);
+
+	/* Set proper VCLK Polarity, else colors will be wrong during playback */
+	//btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR);
+
+	/* code base address */
+	reg = virt_to_bus(zr->stat_com);
+	btwrite(reg, ZR36057_JCBA);
+
+	/* FIFO threshold (FIFO is 160. double words) */
+	/* NOTE: decimal values here */
+	switch (mode) {
+
+	case BUZ_MODE_STILL_COMPRESS:
+	case BUZ_MODE_MOTION_COMPRESS:
+		reg = 140;
+		break;
+
+	case BUZ_MODE_STILL_DECOMPRESS:
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		reg = 20;
+		break;
+
+	default:
+		reg = 80;
+		break;
+
+	}
+	btwrite(reg, ZR36057_JCFT);
+	zr36057_adjust_vfe(zr, mode);
+
+}
+
+#if (DEBUGLEVEL > 2)
+static void dump_guests(struct zoran *zr)
+{
+	int i, guest[8];
+
+	for (i = 1; i < 8; i++) {	// Don't read zr36060 here
+		guest[i] = post_office_read(zr, i, 0);
+	}
+
+	printk(KERN_INFO "%s: Guests:", zr->name);
+
+	for (i = 1; i < 8; i++) {
+		printk(" 0x%02x", guest[i]);
+	}
+	printk("\n");
+}
+
+static unsigned long get_time(void)
+{
+	struct timeval tv;
+	do_gettimeofday(&tv);
+	return (1000000 * tv.tv_sec + tv.tv_usec);
+}
+
+static void detect_guest_activity(struct zoran *zr)
+{
+	int timeout, i, j, res, guest[8], guest0[8], change[8][3];
+	unsigned long t0, t1;
+
+	dump_guests(zr);
+	printk(KERN_INFO "%s: Detecting guests activity, please wait...\n",
+	       zr->name);
+	for (i = 1; i < 8; i++) {	// Don't read zr36060 here
+		guest0[i] = guest[i] = post_office_read(zr, i, 0);
+	}
+
+	timeout = 0;
+	j = 0;
+	t0 = get_time();
+	while (timeout < 10000) {
+		udelay(10);
+		timeout++;
+		for (i = 1; (i < 8) && (j < 8); i++) {
+			res = post_office_read(zr, i, 0);
+			if (res != guest[i]) {
+				t1 = get_time();
+				change[j][0] = (t1 - t0);
+				t0 = t1;
+				change[j][1] = i;
+				change[j][2] = res;
+				j++;
+				guest[i] = res;
+			}
+		}
+		if (j >= 8)
+			break;
+	}
+	printk(KERN_INFO "%s: Guests:", zr->name);
+
+	for (i = 1; i < 8; i++) {
+		printk(" 0x%02x", guest0[i]);
+	}
+	printk("\n");
+	if (j == 0) {
+		printk(KERN_INFO "%s: No activity detected.\n", zr->name);
+		return;
+	}
+	for (i = 0; i < j; i++) {
+		printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", zr->name,
+		       change[i][0], change[i][1], change[i][2]);
+	}
+}
+#endif
+
+static void print_interrupts(struct zoran *zr)
+{
+	int res, noerr;
+	noerr = 0;
+	printk(KERN_INFO "%s: interrupts received:", zr->name);
+	if ((res = zr->field_counter) < -1 || res > 1) {
+		printk(" FD:%d", res);
+	}
+	if ((res = zr->intr_counter_GIRQ1) != 0) {
+		printk(" GIRQ1:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_GIRQ0) != 0) {
+		printk(" GIRQ0:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_CodRepIRQ) != 0) {
+		printk(" CodRepIRQ:%d", res);
+		noerr++;
+	}
+	if ((res = zr->intr_counter_JPEGRepIRQ) != 0) {
+		printk(" JPEGRepIRQ:%d", res);
+		noerr++;
+	}
+	if (zr->JPEG_max_missed) {
+		printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed,
+		       zr->JPEG_min_missed);
+	}
+	if (zr->END_event_missed) {
+		printk(" ENDs missed: %d", zr->END_event_missed);
+	}
+	//if (zr->jpg_queued_num) {
+	printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail,
+	       zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head);
+	//}
+	if (!noerr) {
+		printk(": no interrupts detected.");
+	}
+	printk("\n");
+}
+
+static void clear_interrupt_counters(struct zoran *zr)
+{
+	zr->intr_counter_GIRQ1 = 0;
+	zr->intr_counter_GIRQ0 = 0;
+	zr->intr_counter_CodRepIRQ = 0;
+	zr->intr_counter_JPEGRepIRQ = 0;
+	zr->field_counter = 0;
+	zr->IRQ1_in = 0;
+	zr->IRQ1_out = 0;
+	zr->JPEG_in = 0;
+	zr->JPEG_out = 0;
+	zr->JPEG_0 = 0;
+	zr->JPEG_1 = 0;
+	zr->END_event_missed = 0;
+	zr->JPEG_missed = 0;
+	zr->JPEG_max_missed = 0;
+	zr->JPEG_min_missed = 0x7fffffff;
+}
+
+static u32 count_reset_interrupt(struct zoran *zr)
+{
+	u32 isr;
+	if ((isr = btread(ZR36057_ISR) & 0x78000000)) {
+		if (isr & ZR36057_ISR_GIRQ1) {
+			btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR);
+			zr->intr_counter_GIRQ1++;
+		}
+		if (isr & ZR36057_ISR_GIRQ0) {
+			btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR);
+			zr->intr_counter_GIRQ0++;
+		}
+		if (isr & ZR36057_ISR_CodRepIRQ) {
+			btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR);
+			zr->intr_counter_CodRepIRQ++;
+		}
+		if (isr & ZR36057_ISR_JPEGRepIRQ) {
+			btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR);
+			zr->intr_counter_JPEGRepIRQ++;
+		}
+	}
+	return isr;
+}
+
+static void jpeg_start(struct zoran *zr)
+{
+	int reg;
+	zr->frame_num = 0;
+
+	btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC);	// /P_Reset
+	btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR);	// \CFlush
+	btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC);	// /CodTrnsEn
+	btwrite(IRQ_MASK, ZR36057_ISR);	// Clear IRQs
+	btwrite(IRQ_MASK | ZR36057_ICR_IntPinEn, ZR36057_ICR);	// Enable IRQs
+
+	set_frame(zr, 0);	// \FRAME
+
+	/* JPEG codec guest ID */
+	reg =
+	    (1 << ZR36057_JCGI_JPEGuestID) | (0 <<
+					      ZR36057_JCGI_JPEGuestReg);
+	btwrite(reg, ZR36057_JCGI);
+
+	btor(ZR36057_JPC_Active, ZR36057_JPC);	// /Active
+	btor(ZR36057_JMC_Go_en, ZR36057_JMC);	// /Go_en
+	udelay(30);
+	set_frame(zr, 1);	// /FRAME
+}
+
+static void zr36057_enable_jpg(struct zoran *zr,
+			       enum zoran_codec_mode mode)
+{
+	static int zero = 0;
+	static int one = 1;
+
+	zr->codec_mode = mode;
+	switch (mode) {
+
+	case BUZ_MODE_MOTION_COMPRESS:
+		set_videobus_enable(zr, 0);
+		set_videobus_dir(zr, 0);	// GPIO(zr, 1, 0);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
+				   DECODER_ENABLE_OUTPUT, &one);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
+				   ENCODER_SET_INPUT, &zero);
+		set_videobus_enable(zr, 1);
+		zr36060_sleep(zr, 0);
+		zr36060_set_cap(zr, mode);	// Load ZR36060
+		init_jpeg_queue(zr);
+		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
+
+		clear_interrupt_counters(zr);
+		DEBUG1(printk
+		       (KERN_INFO "%s: enable_jpg MOTION_COMPRESS\n",
+			zr->name));
+		break;
+
+	case BUZ_MODE_MOTION_DECOMPRESS:
+		set_videobus_enable(zr, 0);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
+				   DECODER_ENABLE_OUTPUT, &zero);
+		set_videobus_dir(zr, 1);	// GPIO(zr, 1, 1);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
+				   ENCODER_SET_INPUT, &one);
+		set_videobus_enable(zr, 1);
+		zr36060_sleep(zr, 0);
+		zr36060_set_cap(zr, mode);	// Load ZR36060
+		init_jpeg_queue(zr);
+		zr36057_set_jpg(zr, mode);	// \P_Reset, ... Video param, FIFO
+
+		clear_interrupt_counters(zr);
+		DEBUG1(printk
+		       (KERN_INFO "%s: enable_jpg MOTION_DECOMPRESS\n",
+			zr->name));
+		break;
+
+	case BUZ_MODE_IDLE:
+	default:
+		/* shut down processing */
+		btand(~(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ),
+		      ZR36057_ICR);
+		btwrite(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ,
+			ZR36057_ISR);
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);	// \Go_en
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/20);
+
+		set_videobus_dir(zr, 0);	// GPIO(zr, 1, 0);
+		set_frame(zr, 1);	//GPIO(zr, 6, 1);     // /FRAME
+		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);	// /CFlush
+		btwrite(0, ZR36057_JPC);	// \P_Reset,\CodTrnsEn,\Active
+		btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC);
+		btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC);
+		zr36060_reset(zr);
+		zr36060_sleep(zr, 1);
+		zr36057_adjust_vfe(zr, mode);
+		set_videobus_enable(zr, 0);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
+				   DECODER_ENABLE_OUTPUT, &one);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
+				   ENCODER_SET_INPUT, &zero);
+		set_videobus_enable(zr, 1);
+		DEBUG1(printk
+		       (KERN_INFO "%s: enable_jpg IDLE\n", zr->name));
+		break;
+
+	}
+}
+
+/*
+ *   Queue a MJPEG buffer for capture/playback
+ */
+
+static int jpg_qbuf(struct zoran *zr, int frame,
+		    enum zoran_codec_mode mode)
+{
+	unsigned long flags;
+	int res;
+
+	/* Check if buffers are allocated */
+
+	if (!zr->jpg_buffers_allocated) {
+		printk(KERN_ERR
+		       "%s: jpg_qbuf: buffers not yet allocated\n",
+		       zr->name);
+		return -ENOMEM;
+	}
+
+	/* Does the user want to stop streaming? */
+
+	if (frame < 0) {
+		if (zr->codec_mode == mode) {
+			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+			return 0;
+		} else {
+			printk(KERN_ERR
+			       "%s: jpg_qbuf - stop streaming but not in streaming mode\n",
+			       zr->name);
+			return -EINVAL;
+		}
+	}
+
+	/* No grabbing outside the buffer range! */
+
+	if (frame >= zr->jpg_nbufs) {
+		printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n",
+		       zr->name, frame);
+		return -EINVAL;
+	}
+
+	/* what is the codec mode right now? */
+
+	if (zr->codec_mode == BUZ_MODE_IDLE) {
+		/* Ok load up the zr36060 */
+		zr36057_enable_jpg(zr, mode);
+	} else if (zr->codec_mode != mode) {
+		/* wrong codec mode active - invalid */
+		printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n",
+		       zr->name);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	/* make sure a grab isn't going on currently with this buffer */
+
+	switch (zr->jpg_gbuf[frame].state) {
+
+	case BUZ_STATE_DONE:
+		DEBUG1(printk
+		       (KERN_WARNING
+			"%s: Warning: queing frame in BUZ_STATE_DONE state\n",
+			zr->name));
+	case BUZ_STATE_USER:
+		/* since there is at least one unused buffer there's room for at least one more pend[] entry */
+		zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame;
+		zr->jpg_gbuf[frame].state = BUZ_STATE_PEND;
+		zoran_feed_stat_com(zr);
+		res = 0;
+		break;
+
+	default:
+	case BUZ_STATE_DMA:
+	case BUZ_STATE_PEND:
+		res = -EBUSY;	/* what are you doing? */
+		break;
+
+	}
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	/* Start the zr36060 when the first frame is queued  */
+	if (zr->jpg_que_head == 1)
+		jpeg_start(zr);
+
+	return res;
+}
+
+/*
+ *   Sync on a MJPEG buffer
+ */
+
+static int jpg_sync(struct zoran *zr, struct zoran_sync *bs)
+{
+	unsigned long flags;
+	int frame, timeout;
+
+	if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS
+	    && zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) {
+		DEBUG1(printk(KERN_ERR
+		       "%s: BUZIOCSYNC: - codec not in streaming mode\n",
+		       zr->name));
+		return -EINVAL;
+	}
+	while (zr->jpg_que_tail == zr->jpg_dma_tail) {
+		if (zr->jpg_dma_tail == zr->jpg_dma_head)
+			break;
+		timeout =
+		    interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ);
+		if (!timeout) {
+			btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+			udelay(1);
+			printk(KERN_ERR
+			       "%s: timeout: codec isr=0x%02x, csr=0x%02x\n",
+			       zr->name, zr36060_read_8(zr, 0x008),
+			       zr36060_read_8(zr, 0x001));
+			return -ETIME;
+		} else if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	spin_lock_irqsave(&zr->lock, flags);
+
+	if (zr->jpg_dma_tail != zr->jpg_dma_head)
+		frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME];
+	else
+		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
+	/* buffer should now be in BUZ_STATE_DONE */
+
+#if(DEBUGLEVEL > 0)
+	if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE)
+		printk(KERN_ERR "%s: jpg_sync - internal error\n",
+		       zr->name);
+#endif
+
+	*bs = zr->jpg_gbuf[frame].bs;
+	zr->jpg_gbuf[frame].state = BUZ_STATE_USER;
+
+	spin_unlock_irqrestore(&zr->lock, flags);
+
+	return 0;
+}
+
+/* when this is called the spinlock must be held */
+static void zoran_feed_stat_com(struct zoran *zr)
+{
+	/* move frames from pending queue to DMA */
+
+	int frame, i, max_stat_com;
+
+	max_stat_com =
+	    (zr->params.TmpDcm ==
+	     1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1);
+
+	while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com
+	       && zr->jpg_dma_head < zr->jpg_que_head) {
+
+		frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME];
+		if (zr->params.TmpDcm == 1) {
+			/* fill 1 stat_com entry */
+			i = (zr->jpg_dma_head -
+			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+			if (!(zr->stat_com[i] & 1))
+				break;
+			zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
+		} else {
+			/* fill 2 stat_com entries */
+			i = ((zr->jpg_dma_head -
+			      zr->jpg_err_shift) & 1) * 2;
+			if (!(zr->stat_com[i] & 1))
+				break;
+			zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus;
+			zr->stat_com[i + 1] =
+			    zr->jpg_gbuf[frame].frag_tab_bus;
+		}
+		zr->jpg_gbuf[frame].state = BUZ_STATE_DMA;
+		zr->jpg_dma_head++;
+
+	}
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+		zr->jpg_queued_num++;
+}
+
+/* when this is called the spinlock must be held */
+static void zoran_reap_stat_com(struct zoran *zr)
+{
+	/* move frames from DMA queue to done queue */
+
+	int i;
+	u32 stat_com;
+	unsigned int seq;
+	unsigned int dif;
+	int frame;
+	struct zoran_gbuffer *gbuf;
+
+	/* In motion decompress we don't have a hardware frame counter,
+	   we just count the interrupts here */
+
+	if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+		zr->jpg_seq_num++;
+	}
+	while (zr->jpg_dma_tail < zr->jpg_dma_head) {
+		if (zr->params.TmpDcm == 1)
+			i = (zr->jpg_dma_tail -
+			     zr->jpg_err_shift) & BUZ_MASK_STAT_COM;
+		else
+			i = ((zr->jpg_dma_tail -
+			      zr->jpg_err_shift) & 1) * 2 + 1;
+
+		stat_com = zr->stat_com[i];
+
+		if ((stat_com & 1) == 0) {
+			return;
+		}
+		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
+		gbuf = &zr->jpg_gbuf[frame];
+		get_fast_time(&gbuf->bs.timestamp);
+
+		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
+			gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
+
+			/* update sequence number with the help of the counter in stat_com */
+
+			seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff;
+			dif = (seq - zr->jpg_seq_num) & 0xff;
+			zr->jpg_seq_num += dif;
+		} else {
+			gbuf->bs.length = 0;
+		}
+		gbuf->bs.seq =
+		    zr->params.TmpDcm ==
+		    2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num;
+		gbuf->state = BUZ_STATE_DONE;
+
+		zr->jpg_dma_tail++;
+	}
+}
+
+static void error_handler(struct zoran *zr, u32 astat, u32 stat)
+{
+	/* This is JPEG error handling part */
+	if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS)
+	    && (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) {
+		//printk(KERN_ERR "%s: Internal error: error handling request in mode %d\n", zr->name, zr->codec_mode);
+		return;
+	}
+	if ((stat & 1) == 0
+	    && zr->codec_mode == BUZ_MODE_MOTION_COMPRESS
+	    && zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_nbufs) {
+		/* No free buffers... */
+		zoran_reap_stat_com(zr);
+		zoran_feed_stat_com(zr);
+		wake_up_interruptible(&zr->jpg_capq);
+		zr->JPEG_missed = 0;
+		return;
+	}
+	if (zr->JPEG_error != 1) {
+		/*
+		 * First entry: error just happened during normal operation
+		 * 
+		 * In BUZ_MODE_MOTION_COMPRESS:
+		 * 
+		 * Possible glitch in TV signal. In this case we should
+		 * stop the codec and wait for good quality signal before
+		 * restarting it to avoid further problems
+		 * 
+		 * In BUZ_MODE_MOTION_DECOMPRESS:
+		 * 
+		 * Bad JPEG frame: we have to mark it as processed (codec crashed
+		 * and was not able to do it itself), and to remove it from queue.
+		 */
+		btand(~ZR36057_JMC_Go_en, ZR36057_JMC);
+		udelay(1);
+		stat =
+		    stat | (post_office_read(zr, 7, 0) & 3) << 8 |
+		    zr36060_read_8(zr, 0x008);
+		btwrite(0, ZR36057_JPC);
+		btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR);
+		zr36060_reset(zr);
+		zr36060_sleep(zr, 1);
+		zr->JPEG_error = 1;
+		zr->num_errors++;
+		/* Report error */
+#if(DEBUGLEVEL > 1)
+		if (zr->num_errors <= 8) {
+			long frame;
+			frame =
+			    zr->jpg_pend[zr->
+					 jpg_dma_tail & BUZ_MASK_FRAME];
+			printk(KERN_ERR
+			       "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ",
+			       zr->name, stat, zr->last_isr,
+			       zr->jpg_que_tail, zr->jpg_dma_tail,
+			       zr->jpg_dma_head, zr->jpg_que_head,
+			       zr->jpg_seq_num, frame);
+			printk("stat_com frames:");
+			{
+				int i, j;
+				for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+					for (i = 0; i < zr->jpg_nbufs; i++) {
+						if (zr->stat_com[j] ==
+						    zr->jpg_gbuf[i].
+						    frag_tab_bus) {
+							printk("% d->%d",
+							       j, i);
+						}
+					}
+				}
+				printk("\n");
+			}
+		}
+#endif
+		/* Find an entry in stat_com and rotate contents */
+		{
+			int i;
+
+			if (zr->params.TmpDcm == 1)
+				i = (zr->jpg_dma_tail -
+				     zr->
+				     jpg_err_shift) & BUZ_MASK_STAT_COM;
+			else
+				i = ((zr->jpg_dma_tail -
+				      zr->jpg_err_shift) & 1) * 2;
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) {
+				/* Mimic zr36067 operation */
+				zr->stat_com[i] |= 1;
+				if (zr->params.TmpDcm != 1)
+					zr->stat_com[i + 1] |= 1;
+				/* Refill */
+				zoran_reap_stat_com(zr);
+				zoran_feed_stat_com(zr);
+				wake_up_interruptible(&zr->jpg_capq);
+				/* Find an entry in stat_com again after refill */
+				if (zr->params.TmpDcm == 1)
+					i = (zr->jpg_dma_tail -
+					     zr->
+					     jpg_err_shift) &
+					    BUZ_MASK_STAT_COM;
+				else
+					i = ((zr->jpg_dma_tail -
+					      zr->jpg_err_shift) & 1) * 2;
+			}
+			if (i) {
+				/* Rotate stat_comm entries to make current entry first */
+				int j;
+				u32 bus_addr[BUZ_NUM_STAT_COM];
+
+				memcpy(bus_addr, zr->stat_com,
+				       sizeof(bus_addr));
+				for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+					zr->stat_com[j] =
+					    bus_addr[(i +
+						      j) &
+						     BUZ_MASK_STAT_COM];
+				}
+				zr->jpg_err_shift += i;
+				zr->jpg_err_shift &= BUZ_MASK_STAT_COM;
+			}
+			if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+				zr->jpg_err_seq = zr->jpg_seq_num;	/* + 1; */
+		}
+	}
+	/* Now the stat_comm buffer is ready for restart */
+	{
+		int status;
+
+		status = 0;
+		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_GET_STATUS, &status);
+		if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS
+		    || (status & DECODER_STATUS_GOOD)) {
+	    /********** RESTART code *************/
+			zr36060_reset(zr);
+			zr36060_set_cap(zr, zr->codec_mode);
+			zr36057_set_jpg(zr, zr->codec_mode);
+			jpeg_start(zr);
+#if(DEBUGLEVEL > 1)
+			if (zr->num_errors <= 8)
+				printk(KERN_INFO "%s: Restart\n",
+				       zr->name);
+#endif
+			zr->JPEG_missed = 0;
+			zr->JPEG_error = 2;
+	    /********** End RESTART code ***********/
+		}
+	}
+}
+
+static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 stat, astat;
+	int count;
+	struct zoran *zr;
+	unsigned long flags;
+
+	zr = (struct zoran *) dev_id;
+	count = 0;
+
+	if (zr->testing) {
+		/* Testing interrupts */
+		spin_lock_irqsave(&zr->lock, flags);
+		while ((stat = count_reset_interrupt(zr))) {
+			if (count++ > 100) {
+				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+				printk(KERN_ERR
+				       "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n",
+				       zr->name, stat);
+				wake_up_interruptible(&zr->test_q);
+			}
+		}
+		zr->last_isr = stat;
+		spin_unlock_irqrestore(&zr->lock, flags);
+		return;
+	}
+
+	spin_lock_irqsave(&zr->lock, flags);
+	while (1) {
+		/* get/clear interrupt status bits */
+		stat = count_reset_interrupt(zr);
+		astat = stat & IRQ_MASK;
+		if (!astat) {
+			break;
+		}
+		if (astat & cardvsync[zr->card]) {	// SW
+
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS
+			    || zr->codec_mode ==
+			    BUZ_MODE_MOTION_COMPRESS) {
+				/* count missed interrupts */
+				zr->JPEG_missed++;
+			}
+			//post_office_read(zr,1,0);
+			/* Interrupts may still happen when zr->v4l_memgrab_active is switched off.
+			   We simply ignore them */
+
+			if (zr->v4l_memgrab_active) {
+
+				/* A lot more checks should be here ... */
+				if ((btread(ZR36057_VSSFGR) &
+				     ZR36057_VSSFGR_SnapShot) == 0)
+					printk(KERN_WARNING
+					       "%s: BuzIRQ with SnapShot off ???\n",
+					       zr->name);
+
+				if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) {
+					/* There is a grab on a frame going on, check if it has finished */
+
+					if ((btread(ZR36057_VSSFGR) &
+					     ZR36057_VSSFGR_FrameGrab) ==
+					    0) {
+						/* it is finished, notify the user */
+
+						zr->v4l_gbuf[zr->
+							     v4l_grab_frame].
+						    state = BUZ_STATE_DONE;
+						zr->v4l_grab_frame =
+						    NO_GRAB_ACTIVE;
+						zr->v4l_grab_seq++;
+						zr->v4l_pend_tail++;
+					}
+				}
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE)
+					wake_up_interruptible(&zr->
+							      v4l_capq);
+
+				/* Check if there is another grab queued */
+
+				if (zr->v4l_grab_frame == NO_GRAB_ACTIVE
+				    && zr->v4l_pend_tail !=
+				    zr->v4l_pend_head) {
+
+					int frame =
+					    zr->v4l_pend[zr->
+							 v4l_pend_tail &
+							 V4L_MASK_FRAME];
+					u32 reg;
+
+					zr->v4l_grab_frame = frame;
+
+					/* Set zr36057 video front end and enable video */
+
+					/* Buffer address */
+
+					reg =
+					    zr->v4l_gbuf[frame].
+					    fbuffer_bus;
+					btwrite(reg, ZR36057_VDTR);
+					if (zr->video_interlace)
+						reg += zr->gbpl;
+					btwrite(reg, ZR36057_VDBR);
+
+					/* video stride, status, and frame grab register */
+
+					reg = 0;
+					if (zr->video_interlace)
+						reg += zr->gbpl;
+					reg =
+					    (reg <<
+					     ZR36057_VSSFGR_DispStride);
+					reg |= ZR36057_VSSFGR_VidOvf;
+					reg |= ZR36057_VSSFGR_SnapShot;
+					reg |= ZR36057_VSSFGR_FrameGrab;
+					btwrite(reg, ZR36057_VSSFGR);
+
+					btor(ZR36057_VDCR_VidEn,
+					     ZR36057_VDCR);
+				}
+			}
+		}
+#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ)
+		if (astat & ZR36057_ISR_CodRepIRQ) {
+			zr->intr_counter_CodRepIRQ++;
+			IDEBUG(printk
+			       (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n",
+				zr->name));
+			btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR);
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */
+
+#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ)
+		if (astat & ZR36057_ISR_JPEGRepIRQ) {
+
+			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS
+			    || zr->codec_mode ==
+			    BUZ_MODE_MOTION_COMPRESS) {
+#if(DEBUGLEVEL > 1)
+				if (!zr->frame_num || zr->JPEG_error) {
+					printk(KERN_INFO
+					       "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
+					       zr->name, stat,
+					       zr->params.odd_even,
+					       zr->params.field_per_buff,
+					       zr->JPEG_missed);
+					{
+						char sc[] = "0000";
+						char sv[5];
+						int i;
+						strcpy(sv, sc);
+						for (i = 0; i < 4; i++) {
+							if (zr->
+							    stat_com[i] &
+							    1)
+								sv[i] =
+								    '1';
+						}
+						sv[4] = 0;
+						printk(KERN_INFO
+						       "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
+						       zr->name, sv,
+						       zr->jpg_que_tail,
+						       zr->jpg_dma_tail,
+						       zr->jpg_dma_head,
+						       zr->jpg_que_head);
+					}
+				} else {
+					if (zr->JPEG_missed > zr->JPEG_max_missed)	// Get statistics
+						zr->JPEG_max_missed =
+						    zr->JPEG_missed;
+					if (zr->JPEG_missed <
+					    zr->JPEG_min_missed)
+						zr->JPEG_min_missed =
+						    zr->JPEG_missed;
+				}
+#endif
+#if(DEBUGLEVEL > 2)
+				if (zr->frame_num < 6) {
+					int i;
+					printk("%s: seq=%ld stat_com:",
+					       zr->name, zr->jpg_seq_num);
+					for (i = 0; i < 4; i++) {
+						printk(" %08x",
+						       zr->stat_com[i]);
+					}
+					printk("\n");
+				}
+#endif
+				zr->frame_num++;
+				zr->JPEG_missed = 0;
+				zr->JPEG_error = 0;
+				zoran_reap_stat_com(zr);
+				zoran_feed_stat_com(zr);
+				wake_up_interruptible(&zr->jpg_capq);
+			}	//else {
+			//      printk(KERN_ERR "%s: JPEG interrupt while not in motion (de)compress mode!\n", zr->name);
+			//}
+		}
+#endif				/* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */
+
+		if ((astat & cardjpegint[zr->card])	/* DATERR interrupt received                 */
+		    ||zr->JPEG_missed > 25	/* Too many fields missed without processing */
+		    || zr->JPEG_error == 1	/* We are already in error processing        */
+		    || ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
+			&& (zr->
+			    frame_num & (zr->JPEG_missed >
+					 zr->params.field_per_buff)))
+		    /* fields missed during decompression */
+		    ) {
+			error_handler(zr, astat, stat);
+		}
+
+		count++;
+		if (count > 10) {
+			printk(KERN_WARNING "%s: irq loop %d\n", zr->name,
+			       count);
+			if (count > 20) {
+				btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+				printk(KERN_ERR
+				       "%s: IRQ lockup, cleared int mask\n",
+				       zr->name);
+				break;
+			}
+		}
+		zr->last_isr = stat;
+	}
+	spin_unlock_irqrestore(&zr->lock, flags);
+}
+
+/* Check a zoran_params struct for correctness, insert default params */
+
+static int zoran_check_params(struct zoran *zr,
+			      struct zoran_params *params)
+{
+	int err = 0, err0 = 0;
+
+	/* insert constant params */
+
+	params->major_version = MAJOR_VERSION;
+	params->minor_version = MINOR_VERSION;
+
+	/* Check input and norm: must be set by calling VIDIOCSCHAN only! */
+
+	params->norm = zr->params.norm;
+	params->input = zr->params.input;
+
+	/* Check decimation, set default values for decimation = 1, 2, 4 */
+
+	switch (params->decimation) {
+	case 1:
+
+		params->HorDcm = 1;
+		params->VerDcm = 1;
+		params->TmpDcm = 1;
+		params->field_per_buff = 2;
+
+		params->img_x = 0;
+		params->img_y = 0;
+		params->img_width = zr->timing->Wa;
+		params->img_height = zr->timing->Ha / 2;
+		break;
+
+	case 2:
+
+		params->HorDcm = 2;
+		params->VerDcm = 1;
+		params->TmpDcm = 2;
+		params->field_per_buff = 1;
+
+		params->img_x = 8;
+		params->img_y = 0;
+		params->img_width = zr->timing->Wa;
+		params->img_height = zr->timing->Ha / 2;
+		break;
+
+	case 4:
+
+		params->HorDcm = 4;
+		params->VerDcm = 2;
+		params->TmpDcm = 2;
+		params->field_per_buff = 1;
+
+		params->img_x = 8;
+		params->img_y = 0;
+		params->img_width = zr->timing->Wa;
+		params->img_height = zr->timing->Ha / 2;
+		break;
+
+	case 0:
+
+		/* We have to check the data the user has set */
+
+		if (params->HorDcm != 1 && params->HorDcm != 2
+		    && params->HorDcm != 4)
+			err0++;
+		if (params->VerDcm != 1 && params->VerDcm != 2)
+			err0++;
+		if (params->TmpDcm != 1 && params->TmpDcm != 2)
+			err0++;
+		if (params->field_per_buff != 1
+		    && params->field_per_buff != 2)
+			err0++;
+
+		if (params->img_x < 0)
+			err0++;
+		if (params->img_y < 0)
+			err0++;
+		if (params->img_width < 0)
+			err0++;
+		if (params->img_height < 0)
+			err0++;
+		if (params->img_x + params->img_width > zr->timing->Wa)
+			err0++;
+		if (params->img_y + params->img_height >
+		    zr->timing->Ha / 2)
+			err0++;
+		if (params->HorDcm) {
+			if (params->img_width % (16 * params->HorDcm) != 0)
+				err0++;
+			if (params->img_height % (8 * params->VerDcm) != 0)
+				err0++;
+		}
+
+		if (err0) {
+			DEBUG1(printk(KERN_ERR
+			       "%s: SET PARAMS: error in params for decimation = 0\n",
+			       zr->name));
+			err++;
+		}
+		break;
+
+	default:
+		DEBUG1(printk(KERN_ERR
+		       "%s: SET PARAMS: decimation = %d, must be 0, 1, 2 or 4\n",
+		       zr->name, params->decimation));
+		err++;
+		break;
+	}
+
+	if (params->quality > 100)
+		params->quality = 100;
+	if (params->quality < 5)
+		params->quality = 5;
+
+	if (params->APPn < 0)
+		params->APPn = 0;
+	if (params->APPn > 15)
+		params->APPn = 15;
+	if (params->APP_len < 0)
+		params->APP_len = 0;
+	if (params->APP_len > 60)
+		params->APP_len = 60;
+	if (params->COM_len < 0)
+		params->COM_len = 0;
+	if (params->COM_len > 60)
+		params->COM_len = 60;
+
+	if (err)
+		return -EINVAL;
+
+	return 0;
+
+}
+static void zoran_open_init_params(struct zoran *zr)
+{
+	int i;
+
+	/* Per default, map the V4L Buffers */
+
+	zr->map_mjpeg_buffers = 0;
+
+	/* User must explicitly set a window */
+
+	zr->window_set = 0;
+
+	zr->window.x = 0;
+	zr->window.y = 0;
+	zr->window.width = 0;
+	zr->window.height = 0;
+	zr->window.chromakey = 0;
+	zr->window.flags = 0;
+	zr->window.clips = NULL;
+	zr->window.clipcount = 0;
+
+	zr->video_interlace = 0;
+
+	zr->v4l_memgrab_active = 0;
+	zr->v4l_overlay_active = 0;
+
+	zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+	zr->v4l_grab_seq = 0;
+
+	zr->gwidth = 0;
+	zr->gheight = 0;
+	zr->gformat = 0;
+	zr->gbpl = 0;
+
+	/* DMA ring stuff for V4L */
+
+	zr->v4l_pend_tail = 0;
+	zr->v4l_pend_head = 0;
+	for (i = 0; i < v4l_nbufs; i++) {
+		zr->v4l_gbuf[i].state = BUZ_STATE_USER;	/* nothing going on */
+	}
+
+	/* Set necessary params and call zoran_check_params to set the defaults */
+
+	zr->params.decimation = 1;
+
+	zr->params.quality = 50;	/* default compression factor 8 */
+	if (zr->card != BUZ)
+		zr->params.odd_even = 1;
+	else
+		zr->params.odd_even = 0;
+
+	zr->params.APPn = 0;
+	zr->params.APP_len = 0;	/* No APPn marker */
+	for (i = 0; i < 60; i++)
+		zr->params.APP_data[i] = 0;
+
+	zr->params.COM_len = 0;	/* No COM marker */
+	for (i = 0; i < 60; i++)
+		zr->params.COM_data[i] = 0;
+
+	zr->params.VFIFO_FB = 0;
+
+	memset(zr->params.reserved, 0, sizeof(zr->params.reserved));
+
+	zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+
+	i = zoran_check_params(zr, &zr->params);
+	if (i)
+		printk(KERN_ERR
+		       "%s: zoran_open_init_params internal error\n",
+		       zr->name);
+
+	clear_interrupt_counters(zr);
+	zr->testing = 0;
+}
+
+/*
+ *   Open a zoran card. Right now the flags stuff is just playing
+ */
+
+static int zoran_open(struct video_device *dev, int flags)
+{
+	struct zoran *zr = (struct zoran *) dev;
+	//int one = 1;
+
+	DEBUG1(printk
+	       (KERN_INFO "%s: zoran_open, %s pid=[%d]\n", zr->name,
+		current->comm, current->pid));
+
+	switch (flags) {
+
+	case 0:
+		if (zr->user > 1) {
+			DEBUG1(printk(KERN_WARNING
+			       "%s: zoran_open: Buz is allready in use\n",
+			       zr->name));
+			return -EBUSY;
+		}
+		zr->user++;
+
+		if (zr->user == 1 && v4l_fbuffer_alloc(zr) < 0) {
+			zr->user--;
+			printk(KERN_ERR
+			       "%s: zoran_open: v4l_fbuffer_alloc failed\n",
+			       zr->name);
+			return -ENOMEM;
+		}
+
+		/* default setup */
+
+		if (zr->user == 1) {	/* First device open */
+			zoran_open_init_params(zr);
+
+			zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+
+			btwrite(IRQ_MASK, ZR36057_ISR);	// Clears interrupts
+			btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+			dev->busy = 0;	/* Allow second open */
+		}
+
+		break;
+
+	default:
+		DEBUG1(printk(KERN_WARNING
+		       "%s: zoran_open: flags = 0x%x not yet supported\n",
+		       zr->name, flags));
+		return -EBUSY;
+		break;
+
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void zoran_close(struct video_device *dev)
+{
+	struct zoran *zr = (struct zoran *) dev;
+	int zero = 0, two = 2;
+
+	DEBUG1(printk
+	       (KERN_INFO "%s: zoran_close, %s pid=[%d]\n", zr->name,
+		current->comm, current->pid));
+	/* Clean up JPEG process */
+
+	wake_up_interruptible(&zr->jpg_capq);
+	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+	jpg_fbuffer_free(zr);
+	zr->jpg_nbufs = 0;
+
+	if (zr->user == 1) {	/* Last process */
+		/* disable interrupts */
+		btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+
+#if(DEBUGLEVEL > 1)
+		print_interrupts(zr);
+#endif
+		/* Overlay off */
+		wake_up_interruptible(&zr->v4l_capq);
+		zr36057_set_memgrab(zr, 0);
+		if (zr->v4l_overlay_active)
+			zr36057_overlay(zr, 0);
+		v4l_fbuffer_free(zr);
+
+		if (!pass_through) {	/* Switch to color bar */
+			set_videobus_enable(zr, 0);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_ENABLE_OUTPUT, &zero);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEOENCODER,
+					   ENCODER_SET_INPUT, &two);
+			set_videobus_enable(zr, 1);
+		}
+	}
+
+	zr->user--;
+
+	MOD_DEC_USE_COUNT;
+	DEBUG2(printk(KERN_INFO "%s: zoran_close done\n", zr->name));
+}
+
+
+static long zoran_read(struct video_device *dev, char *buf,
+		       unsigned long count, int nonblock)
+{
+	return -EINVAL;
+}
+
+static long zoran_write(struct video_device *dev, const char *buf,
+			unsigned long count, int nonblock)
+{
+	return -EINVAL;
+}
+
+/*
+ *   ioctl routine
+ */
+
+static int do_zoran_ioctl(struct zoran *zr, unsigned int cmd,
+		       void *arg)
+{
+	switch (cmd) {
+
+	case VIDIOCGCAP:
+		{
+			struct video_capability b;
+			DEBUG2(printk("%s: ioctl VIDIOCGCAP\n", zr->name));
+
+			strncpy(b.name, zr->video_dev.name,
+				sizeof(b.name));
+			b.type =
+			    VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
+			    VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
+			    VID_TYPE_SCALES;
+			/* theoretically we could also flag VID_TYPE_SUBCAPTURE
+			   but this is not even implemented in the BTTV driver */
+
+			if (zr->card == DC10 || zr->card == DC10plus) {
+				b.channels = 3;	/* composite, svhs, internal */
+			} else {
+				b.channels = 2;	/* composite, svhs */
+			}
+			b.audios = 0;
+			b.maxwidth = BUZ_MAX_WIDTH;
+			b.maxheight = BUZ_MAX_HEIGHT;
+			b.minwidth = BUZ_MIN_WIDTH;
+			b.minheight = BUZ_MIN_HEIGHT;
+			if (copy_to_user(arg, &b, sizeof(b))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case VIDIOCGCHAN:
+		{
+			struct video_channel v;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCGCHAN for channel %d\n",
+				zr->name, v.channel));
+			switch (v.channel) {
+			case 0:
+				strcpy(v.name, "Composite");
+				break;
+			case 1:
+				strcpy(v.name, "SVHS");
+				break;
+			case 2:
+				if (zr->card == DC10
+				    || zr->card == DC10plus) {
+					strcpy(v.name, "Internal/comp");
+					break;
+				}
+			default:
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCGCHAN on not existing channel %d\n",
+				       zr->name, v.channel));
+				return -EINVAL;
+			}
+			v.tuners = 0;
+			v.flags = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = zr->params.norm;
+			if (copy_to_user(arg, &v, sizeof(v))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+		/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
+
+		 * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
+		 *                                 ^^^^^^^
+		 * The famos BTTV driver has it implemented with a struct video_channel argument
+		 * and we follow it for compatibility reasons
+		 *
+		 * BTW: this is the only way the user can set the norm!
+		 */
+
+	case VIDIOCSCHAN:
+		{
+			struct video_channel v;
+			int input;
+			int on, res;
+			int encoder_norm;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+
+			if (zr->codec_mode != BUZ_MODE_IDLE) {
+				if (v.norm != zr->params.norm
+				    || v.channel != zr->params.input) {
+					DEBUG1(printk(KERN_ERR
+					       "%s: VIDIOCSCHAN called while the card in capture/playback mode\n",
+					       zr->name));
+					return -EINVAL;
+				} else {
+					DEBUG1(printk(BUZ_WARNING
+					       "%s: Warning: VIDIOCSCHAN called while the card in capture/playback mode\n",
+					       zr->name));
+				}
+			}
+
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCSCHAN: channel=%d, norm=%d\n",
+				zr->name, v.channel, v.norm));
+			switch (v.channel) {
+			case 0:
+				if (zr->card == BUZ)
+					input = 3;
+				else
+					input = 0;
+				break;
+			case 1:
+				input = 7;
+				break;
+			case 2:
+				if (zr->card == DC10
+				    || zr->card == DC10plus) {
+					input = 5;
+					break;
+				}
+			default:
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSCHAN on not existing channel %d\n",
+				       zr->name, v.channel));
+				return -EINVAL;
+				break;
+			}
+
+			if (lock_norm && v.norm != zr->params.norm) {
+				if (lock_norm > 1) {
+					DEBUG1(printk(KERN_WARNING
+					       "%s: VIDIOCSCHAN: TV standard is locked, can not switch norm.\n",
+					       zr->name));
+					return -EINVAL;
+				} else {
+					DEBUG1(printk(KERN_WARNING
+					       "%s: VIDIOCSCHAN: TV standard is locked, norm was not changed.\n",
+					       zr->name));
+					v.norm = zr->params.norm;
+				}
+			}
+			
+			if(v.norm >= 2)
+				return -EINVAL;
+
+			if (!cardnorms[zr->card][v.norm]) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSCHAN with not supported norm %d\n",
+				       zr->name, v.norm));
+				return -EOPNOTSUPP;
+				break;
+			}
+			encoder_norm = v.norm;
+
+			zr->params.norm = v.norm;
+			zr->params.input = v.channel;
+			zr->timing = cardnorms[zr->card][zr->params.norm];
+
+			/* We switch overlay off and on since a change in the norm
+			   needs different VFE settings */
+
+			on = zr->v4l_overlay_active
+			    && !zr->v4l_memgrab_active;
+			if (on)
+				zr36057_overlay(zr, 0);
+
+			set_videobus_enable(zr, 0);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_NORM,
+					   &zr->params.norm);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEOENCODER,
+					   ENCODER_SET_NORM,
+					   &encoder_norm);
+			set_videobus_enable(zr, 1);
+
+			if (on)
+				zr36057_overlay(zr, 1);
+
+			/* Make sure the changes come into effect */
+			res = wait_grab_pending(zr);
+			if (res)
+				return res;
+
+			return 0;
+		}
+		break;
+
+	case VIDIOCGTUNER:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCGTUNER not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCSTUNER:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCSTUNER not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCGPICT:
+		{
+			struct video_picture p = zr->picture;
+
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCGPICT\n", zr->name));
+			p.depth = zr->buffer.depth;
+			switch (zr->buffer.depth) {
+			case 15:
+				p.palette = VIDEO_PALETTE_RGB555;
+				break;
+
+			case 16:
+				p.palette = VIDEO_PALETTE_RGB565;
+				break;
+
+			case 24:
+				p.palette = VIDEO_PALETTE_RGB24;
+				break;
+
+			case 32:
+				p.palette = VIDEO_PALETTE_RGB32;
+				break;
+			}
+
+			if (copy_to_user(arg, &p, sizeof(p))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case VIDIOCSPICT:
+		{
+			struct video_picture p;
+
+			if (copy_from_user(&p, arg, sizeof(p))) {
+				return -EFAULT;
+			}
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_PICTURE, &p);
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n",
+				zr->name, p.brightness, p.hue, p.colour,
+				p.contrast, p.depth, p.palette));
+			/* The depth and palette values have no meaning to us,
+			   should we return  -EINVAL if they don't fit ? */
+			zr->picture = p;
+			return 0;
+		}
+		break;
+
+	case VIDIOCCAPTURE:
+		{
+			int v, res;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCCAPTURE: %d\n", zr->name,
+				v));
+
+			/* If there is nothing to do, return immediatly */
+
+			if ((v && zr->v4l_overlay_active)
+			    || (!v && !zr->v4l_overlay_active))
+				return 0;
+
+			if (v == 0) {
+				zr->v4l_overlay_active = 0;
+				if (!zr->v4l_memgrab_active)
+					zr36057_overlay(zr, 0);
+				/* When a grab is running, the video simply won't be switched on any more */
+			} else {
+				if (!zr->buffer_set || !zr->window_set) {
+					DEBUG1(printk(KERN_ERR
+					       "%s: VIDIOCCAPTURE: buffer or window not set\n",
+					       zr->name));
+					return -EINVAL;
+				}
+				zr->v4l_overlay_active = 1;
+				if (!zr->v4l_memgrab_active)
+					zr36057_overlay(zr, 1);
+				/* When a grab is running, the video will be switched on when grab is finished */
+			}
+			/* Make sure the changes come into effect */
+			res = wait_grab_pending(zr);
+			if (res)
+				return res;
+			return 0;
+		}
+		break;
+
+	case VIDIOCGWIN:
+		{
+			DEBUG2(printk("%s: ioctl VIDIOCGWIN\n", zr->name));
+			if (copy_to_user
+			    (arg, &zr->window, sizeof(zr->window))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case VIDIOCSWIN:
+		{
+			struct video_clip *vcp;
+			struct video_window vw;
+			struct tvnorm *tvn;
+			int on, end, res, Wa, Ha;
+
+			tvn = zr->timing;
+
+			Wa = tvn->Wa;
+			Ha = tvn->Ha;
+
+			if (copy_from_user(&vw, arg, sizeof(vw))) {
+				return -EFAULT;
+			}
+
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n",
+				zr->name, vw.x, vw.y, vw.width, vw.height,
+				vw.clipcount));
+
+			if (!zr->buffer_set) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSWIN: frame buffer has to be set first\n",
+				       zr->name));
+				return -EINVAL;
+			}
+
+			/*
+			 * The video front end needs 4-byte alinged line sizes, we correct that
+			 * silently here if necessary
+			 */
+
+			if (zr->buffer.depth == 15
+			    || zr->buffer.depth == 16) {
+				end = (vw.x + vw.width) & ~1;	/* round down */
+				vw.x = (vw.x + 1) & ~1;	/* round up */
+				vw.width = end - vw.x;
+			}
+
+			if (zr->buffer.depth == 24) {
+				end = (vw.x + vw.width) & ~3;	/* round down */
+				vw.x = (vw.x + 3) & ~3;	/* round up */
+				vw.width = end - vw.x;
+			}
+
+			if (vw.width > Wa)
+				vw.width = Wa;
+			if (vw.height > Ha)
+				vw.height = Ha;
+
+			/* Check for vaild parameters */
+			if (vw.width < BUZ_MIN_WIDTH
+			    || vw.height < BUZ_MIN_HEIGHT
+			    || vw.width > BUZ_MAX_WIDTH
+			    || vw.height > BUZ_MAX_HEIGHT) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSWIN: width = %d or height = %d invalid\n",
+				       zr->name, vw.width, vw.height));
+				return -EINVAL;
+			}
+
+			zr->window.x = vw.x;
+			zr->window.y = vw.y;
+			zr->window.width = vw.width;
+			zr->window.height = vw.height;
+			zr->window.chromakey = 0;
+			zr->window.flags = 0;	// RJ: Is this intended for interlace on/off ?
+			zr->window.clips = NULL;
+			zr->window.clipcount = vw.clipcount;
+
+			/*
+			 * If an overlay is running, we have to switch it off
+			 * and switch it on again in order to get the new settings in effect.
+			 *
+			 * We also want to avoid that the overlay mask is written
+			 * when an overlay is running.
+			 */
+
+			on = zr->v4l_overlay_active
+			    && !zr->v4l_memgrab_active;
+			if (on)
+				zr36057_overlay(zr, 0);
+
+			/*
+			 *   Write the overlay mask if clips are wanted.
+			 */
+			if (vw.clipcount) {
+				vcp =
+				    vmalloc(sizeof(struct video_clip) *
+					    (vw.clipcount + 4));
+				if (vcp == NULL) {
+					printk(KERN_ERR
+					       "%s: zoran_ioctl: Alloc of clip mask failed\n",
+					       zr->name);
+					return -ENOMEM;
+				}
+				if (copy_from_user
+				    (vcp, vw.clips,
+				     sizeof(struct video_clip) *
+				     vw.clipcount)) {
+					vfree(vcp);
+					return -EFAULT;
+				}
+				write_overlay_mask(zr, vcp, vw.clipcount);
+				vfree(vcp);
+			}
+
+			if (on)
+				zr36057_overlay(zr, 1);
+			zr->window_set = 1;
+
+			/* Make sure the changes come into effect */
+			res = wait_grab_pending(zr);
+			if (res)
+				return res;
+
+			return 0;
+		}
+		break;
+
+	case VIDIOCGFBUF:
+		{
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCGFBUF\n", zr->name));
+			if (copy_to_user
+			    (arg, &zr->buffer, sizeof(zr->buffer))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case VIDIOCSFBUF:
+		{
+			struct video_buffer v;
+
+			/* RJ: Isn't this too restrictive? As long as the user doesn't set
+			   the base address it shouldn't be too dangerous */
+
+			if (!capable(CAP_SYS_ADMIN)) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: Only the superuser may issue VIDIOCSFBUF ioctl\n",
+				       zr->name));
+				return -EPERM;
+			}
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n",
+				zr->name, (u32) v.base, v.width, v.height,
+				v.depth, v.bytesperline));
+			if (zr->v4l_overlay_active) {
+				/* Has the user gotten crazy ... ? */
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSFBUF not allowed when overlay active\n",
+				       zr->name));
+				return -EINVAL;
+			}
+			if (v.depth != 15 && v.depth != 16 && v.depth != 24
+			    && v.depth != 32) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSFBUF: depth=%d not supported\n",
+				       zr->name, v.depth));
+				return -EINVAL;
+			}
+			if (v.height <= 0 || v.width <= 0
+			    || v.bytesperline <= 0) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSFBUF: invalid height/width/bpl value\n",
+				       zr->name));
+				return -EINVAL;
+			}
+			if (v.bytesperline & 3) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: VIDIOCSFBUF: bytesperline must be 4-byte aligned\n",
+				       zr->name));
+				return -EINVAL;
+			}
+			if (v.base) {
+				zr->buffer.base =
+				    (void *) ((unsigned long) v.base & ~3);
+			}
+			zr->buffer.height = v.height;
+			zr->buffer.width = v.width;
+			zr->buffer.depth = v.depth;
+			zr->buffer.bytesperline = v.bytesperline;
+
+			if (zr->buffer.base)
+				zr->buffer_set = 1;
+			zr->window_set = 0;	/* The user should set new window parameters */
+			return 0;
+		}
+		break;
+
+		/* RJ: what is VIDIOCKEY intended to do ??? */
+
+	case VIDIOCKEY:
+		{
+			/* Will be handled higher up .. */
+			DEBUG2(printk("%s: ioctl VIDIOCKEY\n", zr->name));
+			return 0;
+		}
+		break;
+
+	case VIDIOCGFREQ:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCGFREQ not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCSFREQ:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCSFREQ not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCGAUDIO:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCGAUDIO not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCSAUDIO:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCSAUDIO not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCSYNC:
+		{
+			int v;
+
+			if (copy_from_user(&v, arg, sizeof(v))) {
+				return -EFAULT;
+			}
+			DEBUG3(printk
+			       ("%s: ioctl VIDIOCSYNC %d\n", zr->name, v));
+			return v4l_sync(zr, v);
+		}
+		break;
+
+	case VIDIOCMCAPTURE:
+		{
+			struct video_mmap vm;
+
+			if (copy_from_user
+			    ((void *) &vm, (void *) arg, sizeof(vm))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n",
+				zr->name, vm.frame, vm.width, vm.height,
+				vm.format));
+			return v4l_grab(zr, &vm);
+		}
+		break;
+
+	case VIDIOCGMBUF:
+		{
+			struct video_mbuf vm;
+			int i;
+
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCGMBUF\n", zr->name));
+			vm.size = v4l_nbufs * v4l_bufsize;
+			vm.frames = v4l_nbufs;
+			for (i = 0; i < v4l_nbufs; i++) {
+				vm.offsets[i] = i * v4l_bufsize;
+			}
+
+			/* The next mmap will map the V4L buffers */
+			zr->map_mjpeg_buffers = 0;
+
+			if (copy_to_user(arg, &vm, sizeof(vm))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case VIDIOCGUNIT:
+		{
+			struct video_unit vu;
+
+			DEBUG2(printk
+			       ("%s: ioctl VIDIOCGUNIT\n", zr->name));
+			vu.video = zr->video_dev.minor;
+			vu.vbi = VIDEO_NO_UNIT;
+			vu.radio = VIDEO_NO_UNIT;
+			vu.audio = VIDEO_NO_UNIT;
+			vu.teletext = VIDEO_NO_UNIT;
+			if (copy_to_user(arg, &vu, sizeof(vu))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+		/*
+		 * RJ: In principal we could support subcaptures for V4L grabbing.
+		 *     Not even the famous BTTV driver has them, however.
+		 *     If there should be a strong demand, one could consider
+		 *     to implement them.
+		 */
+	case VIDIOCGCAPTURE:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCGCAPTURE not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOCSCAPTURE:
+		{
+			DEBUG1(printk(KERN_ERR
+			       "%s: ioctl VIDIOCSCAPTURE not supported\n",
+			       zr->name));
+			return -EINVAL;
+		}
+		break;
+
+	case BUZIOC_G_PARAMS:
+		{
+			DEBUG2(printk
+			       ("%s: ioctl BUZIOC_G_PARAMS\n", zr->name));
+
+			if (copy_to_user
+			    (arg, &(zr->params), sizeof(zr->params))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case BUZIOC_S_PARAMS:
+		{
+			struct zoran_params bp;
+			/* int input, on; */
+
+			if (zr->codec_mode != BUZ_MODE_IDLE) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: BUZIOC_S_PARAMS called but Buz in capture/playback mode\n",
+				       zr->name));
+				return -EINVAL;
+			}
+
+			if (copy_from_user(&bp, arg, sizeof(bp))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl BUZIOC_S_PARAMS\n", zr->name));
+
+			/* Check the params first before overwriting our internal values */
+
+			if (zoran_check_params(zr, &bp))
+				return -EINVAL;
+
+			zr->params = bp;
+
+			/* Make changes of input and norm go into effect immediatly */
+
+			/* We switch overlay off and on since a change in the norm
+			   needs different VFE settings */
+
+			if (copy_to_user(arg, &bp, sizeof(bp))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case BUZIOC_REQBUFS:
+		{
+			struct zoran_requestbuffers br;
+
+			if (zr->jpg_buffers_allocated) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: BUZIOC_REQBUFS: buffers allready allocated\n",
+				       zr->name));
+				return -EINVAL;
+			}
+			if (copy_from_user(&br, arg, sizeof(br))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl BUZIOC_REQBUFS count = %lu size=%lu\n",
+				zr->name, br.count, br.size));
+
+			/* Enforce reasonable lower and upper limits */
+			if (br.count < 4)
+				br.count = 4;	/* Could be choosen smaller */
+			if (br.count > BUZ_MAX_FRAME)
+				br.count = BUZ_MAX_FRAME;
+			br.size = PAGE_ALIGN(br.size);
+			if (br.size < 8192)
+				br.size = 8192;	/* Arbitrary */
+			/* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
+			if (br.size > (512 * 1024))
+				br.size = (512 * 1024);	/* 512 K should be enough */
+			if (zr->need_contiguous
+			    && br.size > MAX_KMALLOC_MEM)
+				br.size = MAX_KMALLOC_MEM;
+
+			zr->jpg_nbufs = br.count;
+			zr->jpg_bufsize = br.size;
+
+			if (jpg_fbuffer_alloc(zr))
+				return -ENOMEM;
+
+			/* The next mmap will map the MJPEG buffers */
+			zr->map_mjpeg_buffers = 1;
+
+			if (copy_to_user(arg, &br, sizeof(br))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	case BUZIOC_QBUF_CAPT:
+		{
+			int nb;
+
+			if (copy_from_user
+			    ((void *) &nb, (void *) arg, sizeof(int))) {
+				return -EFAULT;
+			}
+			DEBUG4(printk
+			       ("%s: ioctl BUZIOC_QBUF_CAPT %d\n",
+				zr->name, nb));
+			return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS);
+		}
+		break;
+
+	case BUZIOC_QBUF_PLAY:
+		{
+			int nb;
+
+			if (copy_from_user
+			    ((void *) &nb, (void *) arg, sizeof(int))) {
+				return -EFAULT;
+			}
+			DEBUG4(printk
+			       ("%s: ioctl BUZIOC_QBUF_PLAY %d\n",
+				zr->name, nb));
+			return jpg_qbuf(zr, nb,
+					BUZ_MODE_MOTION_DECOMPRESS);
+		}
+		break;
+
+	case BUZIOC_SYNC:
+		{
+			struct zoran_sync bs;
+			int res;
+
+			DEBUG4(printk
+			       ("%s: ioctl BUZIOC_SYNC\n", zr->name));
+			res = jpg_sync(zr, &bs);
+			if (copy_to_user(arg, &bs, sizeof(bs))) {
+				return -EFAULT;
+			}
+			return res;
+		}
+		break;
+
+	case BUZIOC_G_STATUS:
+		{
+			struct zoran_status bs;
+			int norm, input, status;
+			unsigned long timeout;
+
+			if (zr->codec_mode != BUZ_MODE_IDLE) {
+				DEBUG1(printk(KERN_ERR
+				       "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
+				       zr->name));
+				return -EINVAL;
+			}
+
+			if (copy_from_user(&bs, arg, sizeof(bs))) {
+				return -EFAULT;
+			}
+			DEBUG2(printk
+			       ("%s: ioctl BUZIOC_G_STATUS\n", zr->name));
+
+			switch (bs.input) {
+			case 0:
+				if (zr->card == BUZ)
+					input = 3;
+				else
+					input = 0;
+				break;
+			case 1:
+				input = 7;
+				break;
+			default:
+				DEBUG1(printk(KERN_ERR
+				       "%s: BUZIOC_G_STATUS on not existing input %d\n",
+				       zr->name, bs.input));
+				return -EINVAL;
+			}
+
+			/* Set video norm to VIDEO_MODE_AUTO */
+
+			norm = VIDEO_MODE_AUTO;
+			set_videobus_enable(zr, 0);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_NORM, &norm);
+			set_videobus_enable(zr, 1);
+
+			/* sleep 1 second */
+
+			timeout = jiffies + 1 * HZ;
+			while (jiffies < timeout)
+				schedule();
+
+			/* Get status of video decoder */
+
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_GET_STATUS, &status);
+			bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0;
+
+			if (status & DECODER_STATUS_NTSC)
+				bs.norm = VIDEO_MODE_NTSC;
+			else if (status & DECODER_STATUS_SECAM)
+				bs.norm = VIDEO_MODE_SECAM;
+			else
+				bs.norm = VIDEO_MODE_PAL;
+
+			bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0;
+
+			/* restore previous input and norm */
+			if (zr->card == BUZ)
+				input = zr->params.input == 0 ? 3 : 7;
+			else
+				input = zr->params.input == 0 ? 0 : 7;
+			set_videobus_enable(zr, 0);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_INPUT, &input);
+			i2c_control_device(&zr->i2c,
+					   I2C_DRIVERID_VIDEODECODER,
+					   DECODER_SET_NORM,
+					   &zr->params.norm);
+			set_videobus_enable(zr, 1);
+
+			if (copy_to_user(arg, &bs, sizeof(bs))) {
+				return -EFAULT;
+			}
+			return 0;
+		}
+		break;
+
+	default:
+		DEBUG1(printk
+		       ("%s: UNKNOWN ioctl cmd: 0x%x\n", zr->name, cmd));
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct zoran *zr = (struct zoran *) dev;
+	int err;
+	
+	down(&zr->sem);
+	err = do_zoran_ioctl(zr, cmd, arg);
+	up(&zr->sem);
+	
+	return err;
+}
+
+/*
+ *   This maps the buffers to user space.
+ *
+ *   Depending on the state of zr->map_mjpeg_buffers
+ *   the V4L or the MJPEG buffers are mapped
+ *
+ */
+
+static int do_zoran_mmap(struct zoran *zr, const char *adr,
+		      unsigned long size)
+{
+	unsigned long start = (unsigned long) adr;
+	unsigned long page, pos, todo, fraglen;
+	int i, j;
+
+	DEBUG2(printk
+	       (KERN_INFO "%s: mmap at 0x%08lx, size %lu\n", zr->name,
+		start, size));
+	if (zr->map_mjpeg_buffers) {
+		/* Map the MJPEG buffers */
+
+		if (!zr->jpg_buffers_allocated) {
+			DEBUG1(printk(KERN_ERR
+			       "%s: zoran_mmap(MJPEG): buffers not yet allocated\n",
+			       zr->name));
+			return -ENOMEM;
+		}
+
+		if (size > zr->jpg_nbufs * zr->jpg_bufsize) {
+			DEBUG1(printk(KERN_ERR
+			       "%s: zoran_mmap(MJPEG): Max size is %lu - you wanted %lu\n",
+			       zr->name, zr->jpg_nbufs * zr->jpg_bufsize,
+			       size));
+			return -EINVAL;
+		}
+
+		if (size != zr->jpg_nbufs * zr->jpg_bufsize)
+			DEBUG1(printk(KERN_WARNING
+			       "%s: zoran_mmap(MJPEG): Expected %lu - you wanted %lu\n",
+			       zr->name, zr->jpg_nbufs * zr->jpg_bufsize,
+			       size));
+
+		for (i = 0; i < zr->jpg_nbufs; i++) {
+			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) {
+				fraglen =
+				    (zr->jpg_gbuf[i].
+				     frag_tab[2 * j + 1] & ~1) << 1;
+				todo = size;
+				if (todo > fraglen)
+					todo = fraglen;
+				pos =
+				    (unsigned long) zr->jpg_gbuf[i].
+				    frag_tab[2 * j];
+				page = virt_to_phys(bus_to_virt(pos));	/* should just be pos on i386 */
+				if (remap_page_range
+				    (start, page, todo, PAGE_SHARED)) {
+					printk(KERN_ERR
+					       "%s: zoran_mmap(V4L): remap_page_range failed\n",
+					       zr->name);
+					return -EAGAIN;
+				}
+				size -= todo;
+				start += todo;
+				if (size == 0)
+					break;
+				if (zr->jpg_gbuf[i].
+				    frag_tab[2 * j + 1] & 1)
+					break;	/* was last fragment */
+			}
+			if (size == 0)
+				break;
+		}
+	} else {
+		/* Map the V4L buffers */
+
+		if (size > v4l_nbufs * v4l_bufsize) {
+			DEBUG1(printk(KERN_ERR
+			       "%s: zoran_mmap(V4L): Max size is %d - you wanted %ld\n",
+			       zr->name, v4l_nbufs * v4l_bufsize, size));
+			return -EINVAL;
+		}
+
+		if (size != v4l_nbufs * v4l_bufsize)
+			DEBUG1(printk(KERN_WARNING
+			       "%s: zoran_mmap(V4L): Expected %d - you wanted %ld\n",
+			       zr->name, v4l_nbufs * v4l_bufsize, size));
+
+		for (i = 0; i < v4l_nbufs; i++) {
+			todo = size;
+			if (todo > v4l_bufsize)
+				todo = v4l_bufsize;
+			page = zr->v4l_gbuf[i].fbuffer_phys;
+			DEBUG2(printk
+			       ("V4L remap page range %d 0x%lx %ld to 0x%lx\n",
+				i, page, todo, start));
+			if (remap_page_range
+			    (start, page, todo, PAGE_SHARED)) {
+				printk(KERN_ERR
+				       "%s: zoran_mmap(V4L): remap_page_range failed\n",
+				       zr->name);
+				return -EAGAIN;
+			}
+			size -= todo;
+			start += todo;
+			if (size == 0)
+				break;
+		}
+	}
+	return 0;
+}
+
+static int zoran_mmap(struct video_device *dev, const char *adr,
+		      unsigned long size)
+{
+	int err;
+	struct zoran *zr = (struct zoran *) dev;
+	
+	down(&zr->sem);
+	err = do_zoran_mmap(zr, adr, size);
+	up(&zr->sem);
+		
+	return err;
+}
+
+static int zoran_init_done(struct video_device *dev)
+{
+	return 0;
+}
+
+static struct video_device zoran_template = {
+	THIS_MODULE,
+	ZORAN_NAME,
+	VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
+	    VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
+	ZORAN_HARDWARE,
+	zoran_open,
+	zoran_close,
+	zoran_read,
+	zoran_write,
+	NULL,
+	zoran_ioctl,
+	zoran_mmap,
+	zoran_init_done,
+	NULL,
+	0,
+	0
+};
+
+/*
+ * initialize video front end
+ */
+static void zr36057_init_vfe(struct zoran *zr)
+{
+	u32 reg;
+	reg = btread(ZR36057_VFESPFR);
+	reg |= ZR36057_VFESPFR_LittleEndian;
+	reg &= ~ZR36057_VFESPFR_VCLKPol;
+	reg |= ZR36057_VFESPFR_ExtFl;
+	reg |= ZR36057_VFESPFR_TopField;
+	btwrite(reg, ZR36057_VFESPFR);
+	reg = btread(ZR36057_VDCR);
+	if (triton || zr->revision <= 1)
+		reg &= ~ZR36057_VDCR_Triton;
+	else
+		reg |= ZR36057_VDCR_Triton;
+	btwrite(reg, ZR36057_VDCR);
+}
+
+static void test_interrupts(struct zoran *zr)
+{
+	int timeout, icr;
+
+	clear_interrupt_counters(zr);
+	zr->testing = 1;
+	icr = btread(ZR36057_ICR);
+	btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR);
+	timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ);
+	btwrite(0, ZR36057_ICR);
+	btwrite(0x78000000, ZR36057_ISR);
+	zr->testing = 0;
+	printk(KERN_INFO "%s: Testing interrupts...\n", zr->name);
+	if (timeout) {
+		printk(": time spent: %d\n", 1 * HZ - timeout);
+	}
+	print_interrupts(zr);
+	btwrite(icr, ZR36057_ICR);
+}
+
+static int zr36057_init(int i)
+{
+	struct zoran *zr = &zoran[i];
+	unsigned long mem;
+	unsigned mem_needed;
+	int j;
+	int two = 2;
+	int zero = 0;
+
+	printk(KERN_INFO "%s: Initializing card[%d], zr=%x\n", zr->name, i, (int) zr);
+
+	/* default setup of all parameters which will persist beetween opens */
+
+	zr->user = 0;
+
+	init_waitqueue_head(&zr->v4l_capq);
+	init_waitqueue_head(&zr->jpg_capq);
+	init_waitqueue_head(&zr->test_q);
+
+	zr->map_mjpeg_buffers = 0;	/* Map V4L buffers by default */
+
+	zr->jpg_nbufs = 0;
+	zr->jpg_bufsize = 0;
+	zr->jpg_buffers_allocated = 0;
+
+	zr->buffer_set = 0;	/* Flag if frame buffer has been set */
+	zr->buffer.base = (void *) vidmem;
+	zr->buffer.width = 0;
+	zr->buffer.height = 0;
+	zr->buffer.depth = 0;
+	zr->buffer.bytesperline = 0;
+
+	zr->params.norm = default_norm = (default_norm < 3 ? default_norm : VIDEO_MODE_PAL);	/* Avoid nonsense settings from user */
+	if (!(zr->timing = cardnorms[zr->card][zr->params.norm])) {
+		printk(KERN_WARNING
+		       "%s: default TV statdard not supported by hardware. PAL will be used.\n",
+		       zr->name);
+		zr->params.norm = VIDEO_MODE_PAL;
+		zr->timing = cardnorms[zr->card][zr->params.norm];
+	}
+	zr->params.input = default_input = (default_input ? 1 : 0);	/* Avoid nonsense settings from user */
+	zr->video_interlace = 0;
+
+	/* Should the following be reset at every open ? */
+
+	zr->picture.colour = 32768;
+	zr->picture.brightness = 32768;
+	zr->picture.hue = 32768;
+	zr->picture.contrast = 32768;
+	zr->picture.whiteness = 0;
+	zr->picture.depth = 0;
+	zr->picture.palette = 0;
+
+	for (j = 0; j < VIDEO_MAX_FRAME; j++) {
+		zr->v4l_gbuf[i].fbuffer = 0;
+		zr->v4l_gbuf[i].fbuffer_phys = 0;
+		zr->v4l_gbuf[i].fbuffer_bus = 0;
+	}
+
+	zr->stat_com = 0;
+
+	/* default setup (will be repeated at every open) */
+
+	zoran_open_init_params(zr);
+
+	/* allocate memory *before* doing anything to the hardware in case allocation fails */
+
+	/* STAT_COM table and overlay mask */
+
+	mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4;
+	mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
+	if (!mem) {
+		printk(KERN_ERR "%s: zr36057_init: kmalloc (STAT_COM + ovl.mask) failed\n", zr->name);
+		return -ENOMEM;
+	}
+	memset((void *) mem, 0, mem_needed);
+
+	zr->stat_com = (u32 *) mem;
+	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+		zr->stat_com[j] = 1;	/* mark as unavailable to zr36057 */
+	}
+	zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4);
+
+	/* Initialize zr->jpg_gbuf */
+
+	for (j = 0; j < BUZ_MAX_FRAME; j++) {
+		zr->jpg_gbuf[j].frag_tab = 0;
+		zr->jpg_gbuf[j].frag_tab_bus = 0;
+		zr->jpg_gbuf[j].state = BUZ_STATE_USER;
+		zr->jpg_gbuf[j].bs.frame = j;
+	}
+
+	/*
+	 *   Now add the template and register the device unit.
+	 */
+	memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
+	strcpy(zr->video_dev.name, zr->name);
+	if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {
+		i2c_unregister_bus(&zr->i2c);
+		kfree((void *) zr->stat_com);
+		return -1;
+	}
+
+	/* Enable bus-mastering */
+	pci_set_master(zr->pci_dev);
+
+	if (zr->card == BUZ)
+		j = zr->params.input == 0 ? 3 : 7;
+	else
+		j = zr->params.input == 0 ? 0 : 7;
+	set_videobus_enable(zr, 0);
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
+			   DECODER_SET_INPUT, &j);
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
+			   DECODER_SET_NORM, &zr->params.norm);
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
+			   ENCODER_SET_NORM, &zr->params.norm);
+	set_videobus_enable(zr, 1);
+
+	/* toggle JPEG codec sleep to sync PLL */
+	zr36060_sleep(zr, 1);
+	zr36060_sleep(zr, 0);
+
+	/* set individual interrupt enables (without GIRQ1)
+	   but don't global enable until zoran_open() */
+
+	//btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR);  // SW
+	// It looks like using only JPEGRepIRQEn is not always reliable,
+	// may be when JPEG codec crashes it won't generate IRQ? So,
+	btwrite(IRQ_MASK, ZR36057_ICR);	// Enable Vsync interrupts too. SM
+
+	zr36057_init_vfe(zr);
+
+	zr->zoran_proc = NULL;
+	zr->initialized = 1;
+
+	zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+#if (DEBUGLEVEL > 2)
+	detect_guest_activity(zr);
+#endif
+	test_interrupts(zr);
+	btwrite(IRQ_MASK, ZR36057_ICR);	// Enable Vsync interrupts too. SM
+	if (!pass_through) {
+		set_videobus_enable(zr, 0);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER,
+				   DECODER_ENABLE_OUTPUT, &zero);
+		i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER,
+				   ENCODER_SET_INPUT, &two);
+		set_videobus_enable(zr, 1);
+	}
+	return 0;
+}
+
+#include "zoran_procfs.c"
+
+static void release_dc10(void)
+{
+	u8 command;
+	int i;
+	struct zoran *zr;
+
+	for (i = 0; i < zoran_num; i++) {
+		zr = &zoran[i];
+
+		if (!zr->initialized)
+			continue;
+
+		/* unregister i2c_bus */
+		i2c_unregister_bus((&zr->i2c));
+
+		/* disable PCI bus-mastering */
+		pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command);
+		command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command);
+
+		/* put chip into reset */
+		btwrite(0, ZR36057_SPGPPCR);
+
+		free_irq(zr->pci_dev->irq, zr);
+
+		/* unmap and free memory */
+
+		kfree((void *) zr->stat_com);
+
+		zoran_proc_cleanup(i);
+		iounmap(zr->zr36057_mem);
+
+		video_unregister_device(&zr->video_dev);
+	}
+}
+
+/*
+ *   Scan for a Buz card (actually for the PCI contoler ZR36057),
+ *   request the irq and map the io memory
+ */
+
+static int find_zr36057(void)
+{
+	unsigned char latency, need_latency;
+	struct zoran *zr;
+	struct pci_dev *dev = NULL;
+	int result;
+
+	zoran_num = 0;
+
+	while (zoran_num < BUZ_MAX
+	       && (dev =
+		   pci_find_device(PCI_VENDOR_ID_ZORAN,
+				   PCI_DEVICE_ID_ZORAN_36057,
+				   dev)) != NULL) {
+		zr = &zoran[zoran_num];
+		zr->pci_dev = dev;
+		zr->zr36057_mem = NULL;
+		zr->id = zoran_num;
+		sprintf(zr->name, "MJPEG[%u]", zr->id);
+
+		spin_lock_init(&zr->lock);
+		init_MUTEX(&zr->sem);
+
+		if (pci_enable_device(dev))
+			continue;
+
+		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
+		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION,
+				     &zr->revision);
+		if (zr->revision < 2) {
+			printk(KERN_INFO
+			       "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
+			       zr->name, zr->revision, zr->pci_dev->irq,
+			       zr->zr36057_adr);
+		} else {
+			unsigned short ss_vendor_id, ss_id;
+			ss_vendor_id = zr->pci_dev->subsystem_vendor;
+			ss_id = zr->pci_dev->subsystem_device;
+			printk(KERN_INFO
+			       "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n",
+			       zr->name, zr->revision, zr->pci_dev->irq,
+			       zr->zr36057_adr);
+			printk(KERN_INFO
+			       "%s: subsystem vendor=0x%04x id=0x%04x\n",
+			       zr->name, ss_vendor_id, ss_id);
+		}
+
+		zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000);
+		if (!zr->zr36057_mem) {
+			printk(KERN_ERR "%s: ioremap failed\n", zr->name);
+			/* XXX handle error */
+		}
+
+		result = request_irq(zr->pci_dev->irq, zoran_irq, SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr);
+		if (result < 0) {
+			if (result == -EINVAL) {
+				printk(KERN_ERR
+				       "%s: Bad irq number or handler\n",
+				       zr->name);
+			} else if (result == -EBUSY) {
+				printk(KERN_ERR
+				       "%s: IRQ %d busy, change your PnP config in BIOS\n",
+				       zr->name, zr->pci_dev->irq);
+			} else {
+				printk(KERN_ERR
+				       "%s: Can't assign irq, error code %d\n",
+				       zr->name, result);
+			}
+			iounmap(zr->zr36057_mem);
+			continue;
+		}
+
+		/* set PCI latency timer */
+		pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency);
+		need_latency = zr->revision > 1 ? 32 : 48;
+		if (latency != need_latency) {
+			printk(KERN_INFO "%s: Changing PCI latency from %d to %d.\n",  zr->name, latency, need_latency);
+			pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER,  need_latency);
+		}
+
+		btwrite(0, ZR36057_SPGPPCR);
+		mdelay(1);
+		btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR);
+		mdelay(1);
+
+		/* assert P_Reset */
+		btwrite(0, ZR36057_JPC);
+
+		/* set up GPIO direction - all output */
+		btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR);
+		btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1);
+
+		/* i2c */
+		memcpy(&zr->i2c, &zoran_i2c_bus_template,
+		       sizeof(struct i2c_bus));
+		strcpy(zr->i2c.name, zr->name);
+		zr->i2c.data = zr;
+		printk(KERN_INFO "%s: Initializing i2c bus...\n", zr->name);
+		if (i2c_register_bus(&zr->i2c) < 0) {
+			/* put chip into reset */
+			btwrite(0, ZR36057_SPGPPCR);
+			free_irq(zr->pci_dev->irq, zr);
+			iounmap(zr->zr36057_mem);
+			printk(KERN_ERR "%s: Can't initialize i2c bus\n", zr->name);
+			continue;
+		}
+
+		if (zr->card != DC10 && zr->card != DC10plus
+		    && zr->card != LML33 && zr->card != BUZ) {
+			/* unregister i2c_bus */
+			i2c_unregister_bus((&zr->i2c));
+			/* put chip into reset */
+			btwrite(0, ZR36057_SPGPPCR);
+			free_irq(zr->pci_dev->irq, zr);
+			iounmap(zr->zr36057_mem);
+			printk(KERN_ERR "%s: Card not supported\n",
+			       zr->name);
+			continue;
+		}
+		printk(KERN_INFO "%s card detected\n", zr->name);
+		if (zr->card == LML33) {
+			GPIO(zr, 2, 1);	// Set Composite input/output
+		}
+
+		/* reset JPEG codec */
+		zr36060_sleep(zr, 1);
+		zr36060_reset(zr);
+
+		/* video bus enabled */
+
+		/* display codec revision */
+		if (zr36060_read_8(zr, 0x022) == 0x33) {
+			printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
+			       zr->name, zr36060_read_8(zr, 0x023));
+		} else {
+			/* unregister i2c_bus */
+			i2c_unregister_bus((&zr->i2c));
+			/* put chip into reset */
+			btwrite(0, ZR36057_SPGPPCR);
+			free_irq(zr->pci_dev->irq, zr);
+			iounmap(zr->zr36057_mem);
+			printk(KERN_ERR "%s: Zoran ZR36060 not found\n",
+			       zr->name);
+			continue;
+		}
+
+		zoran_num++;
+	}
+	if (zoran_num == 0) {
+		printk(KERN_INFO "No known MJPEG cards found.\n");
+	}
+	return zoran_num;
+}
+
+static void handle_chipset(void)
+{
+	if(pci_pci_problems & PCIPCI_FAIL)
+		printk(KERN_WARNING "Chipset may not support reliable PCI-PCI DMA.\n");
+
+	if(pci_pci_problems & PCIPCI_TRITON)
+	{
+		printk(KERN_WARNING "Enabling Triton support.\n");
+		triton = 1;
+	}
+	
+	if(pci_pci_problems & PCIPCI_NATOMA)
+	{
+		printk(KERN_WARNING "Enabling Natoma workaround.\n");
+		natoma = 1;
+	}
+}
+
+static int init_dc10_cards(void)
+{
+	int i;
+
+	memset(zoran, 0, sizeof(zoran));
+	printk(KERN_INFO
+	       "Zoran ZR36060 + ZR36057/67 MJPEG board driver version %d.%d\n",
+	       MAJOR_VERSION, MINOR_VERSION);
+
+	/* Look for cards */
+
+	if (find_zr36057() < 0) {
+		return -EIO;
+	}
+	if (zoran_num == 0)
+		return 0;	//-ENXIO;
+
+	printk(KERN_INFO "MJPEG: %d card(s) found\n", zoran_num);
+
+	/* check the parameters we have been given, adjust if necessary */
+
+	if (v4l_nbufs < 0)
+		v4l_nbufs = 0;
+	if (v4l_nbufs > VIDEO_MAX_FRAME)
+		v4l_nbufs = VIDEO_MAX_FRAME;
+	/* The user specfies the in KB, we want them in byte (and page aligned) */
+	v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024);
+	if (v4l_bufsize < 32768)
+		v4l_bufsize = 32768;
+	/* 2 MB is arbitrary but sufficient for the maximum possible images */
+	if (v4l_bufsize > 2048 * 1024)
+		v4l_bufsize = 2048 * 1024;
+
+	printk(KERN_INFO "MJPEG: using %d V4L buffers of size %d KB\n",
+	       v4l_nbufs, v4l_bufsize >> 10);
+
+	/* Use parameter for vidmem or try to find a video card */
+
+	if (vidmem) {
+		printk(KERN_INFO
+		       "MJPEG: Using supplied video memory base address @ 0x%lx\n",
+		       vidmem);
+	}
+	/* check if we have a Triton or Natome chipset */
+
+	handle_chipset();
+
+	/* take care of Natoma chipset and a revision 1 zr36057 */
+
+	for (i = 0; i < zoran_num; i++) {
+		if (natoma && zoran[i].revision <= 1) {
+			zoran[i].need_contiguous = 1;
+			printk(KERN_INFO
+			       "%s: ZR36057/Natoma bug, max. buffer size is 128K\n",
+			       zoran[i].name);
+		} else {
+			zoran[i].need_contiguous = 0;
+		}
+	}
+
+	/* initialize the Buzs */
+
+	/* We have to know which ones must be released if an error occurs */
+	for (i = 0; i < zoran_num; i++)
+		zoran[i].initialized = 0;
+
+	for (i = 0; i < zoran_num; i++) {
+		if (zr36057_init(i) < 0) {
+			release_dc10();
+			return -EIO;
+		}
+		zoran_proc_init(i);
+	}
+
+	return 0;
+}
+
+static void unload_dc10_cards(void)
+{
+	release_dc10();
+}
+
+
+module_init(init_dc10_cards);
+module_exit(unload_dc10_cards);
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/Config.in linux/drivers/message/fusion/Config.in
--- v2.4.6/linux/drivers/message/fusion/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/Config.in	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,39 @@
+mainmenu_option next_comment
+comment 'Fusion MPT device support'
+
+dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $CONFIG_BLK_DEV_SD
+
+if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then
+
+  if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
+    define_bool CONFIG_FUSION_BOOT y
+    comment "(ability to boot linux kernel from Fusion device is ENABLED!)"
+  else
+    define_bool CONFIG_FUSION_BOOT n
+    comment "(ability to boot linux kernel from Fusion device is DISABLED!)"
+  fi
+
+  if [ "$CONFIG_MODULES" = "y" ]; then
+    #  How can we force these options to module or nothing?
+    dep_tristate "  Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m
+    dep_tristate "  Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m
+  fi
+
+  dep_tristate "  Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET
+  if [ "$CONFIG_FUSION_LAN" != "n" ]; then
+    define_bool CONFIG_NET_FC y
+  fi
+
+else
+
+  define_bool CONFIG_FUSION_BOOT n
+  # These <should> be define_tristate, but we leave them define_bool
+  # for backward compatibility with pre-linux-2.2.15 kernels.
+  # (Bugzilla:fibrebugs, #384)
+  define_bool CONFIG_FUSION_ISENSE n
+  define_bool CONFIG_FUSION_CTL n
+  define_bool CONFIG_FUSION_LAN n
+
+fi
+
+endmenu
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/Makefile linux/drivers/message/fusion/Makefile
--- v2.4.6/linux/drivers/message/fusion/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/Makefile	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,72 @@
+#
+# Makefile for the LSI Logic Fusion MPT (Message Passing Technology) 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 definition is now inherited from the
+# parent makefile.
+#
+# Note 3! If you want to turn on various debug defines for an extended period of
+# time but don't want them lingering around in the Makefile when you pass it on 
+# to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer
+
+#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC
+
+#  Architecture-specific...
+#			# intel
+#EXTRA_CFLAGS += -g
+#			# sparc64
+#EXTRA_CFLAGS += -gstabs+
+
+EXTRA_CFLAGS += -I. ${MPT_CFLAGS}
+
+# Fusion MPT drivers; recognized debug defines...
+#  MPT general:
+#EXTRA_CFLAGS += -DDEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
+#EXTRA_CFLAGS += -DMPT_DEBUG_SPINLOCK
+# driver/module specifics...
+#  For mptbase:
+#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
+#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
+#  For {mptscsih, mptctl}:
+#CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH
+#CFLAGS_mptscsih.o += -DMPT_SCSI_CACHE_AUTOSENSE
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG
+#CFLAGS_mptctl.o += -DMPT_DEBUG_SG
+#  For mptlan:
+#CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG
+#  For isense:
+
+#  EXP...
+##mptscsih-objs	:= scsihost.o scsiherr.o
+
+#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
+
+O_TARGET := fusion.o
+
+export-objs	:= mptbase.o mptscsih.o mptlan.o mptctl.o isense.o
+
+# ? what's list-multi for?
+#list-multi	:= fusion.o mptscsih.o
+
+obj-$(CONFIG_FUSION)		+= mptbase.o mptscsih.o
+obj-$(CONFIG_FUSION_ISENSE)	+= isense.o
+obj-$(CONFIG_FUSION_CTL)	+= mptctl.o
+obj-$(CONFIG_FUSION_LAN)	+= mptlan.o
+
+O_OBJS		:= $(filter-out		$(export-objs), $(obj-y))
+OX_OBJS		:= $(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
+
+
+#  EXP...
+## Fusion MPT extra's...
+##mptscsih.o: $(mptscsih-objs)
+##	$(LD) -r -o $@ $(mptscsih-objs)
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/ascq_tbl.c linux/drivers/message/fusion/ascq_tbl.c
--- v2.4.6/linux/drivers/message/fusion/ascq_tbl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/ascq_tbl.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,2416 @@
+#ifndef SCSI_ASCQ_TBL_C_INCLUDED
+#define SCSI_ASCQ_TBL_C_INCLUDED
+
+/* AuToMaGiCaLlY generated from: "t10.org/asc-num.txt"
+ *******************************************************************************
+ * File: ASC-NUM.TXT
+ * 
+ * SCSI ASC/ASCQ Assignments
+ * Numeric Sorted Listing
+ * as of  5/18/00
+ * 
+ *          D - DIRECT ACCESS DEVICE (SBC-2)                   device column key
+ *          .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
+ *          . L - PRINTER DEVICE (SSC)                           blank = reserved
+ *          .  P - PROCESSOR DEVICE (SPC)                     not blank = allowed
+ *          .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2)
+ *          .  . R - CD DEVICE (MMC)
+ *          .  .  S - SCANNER DEVICE (SCSI-2)
+ *          .  .  .O - OPTICAL MEMORY DEVICE (SBC-2)
+ *          .  .  . M - MEDIA CHANGER DEVICE (SMC)
+ *          .  .  .  C - COMMUNICATION DEVICE (SCSI-2)
+ *          .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
+ *          .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
+ *          .  .  .  .  B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC)
+ *          .  .  .  .  .K - OPTICAL CARD READER/WRITER DEVICE (OCRW)
+ * ASC/ASCQ DTLPWRSOMCAEBK  Description
+ * -------  --------------  ----------------------------------------------------
+ */
+
+static char SenseDevTypes001[] = "DTLPWRSOMCAEBK";
+static char SenseDevTypes002[] = ".T............";
+static char SenseDevTypes003[] = ".T....S.......";
+static char SenseDevTypes004[] = ".TL...S.......";
+static char SenseDevTypes005[] = ".....R........";
+static char SenseDevTypes006[] = "DTL.WRSOM.AEBK";
+static char SenseDevTypes007[] = "D...W..O....BK";
+static char SenseDevTypes008[] = "D...WR.OM...BK";
+static char SenseDevTypes009[] = "DTL.W.SO....BK";
+static char SenseDevTypes010[] = "DTL..R.O....B.";
+static char SenseDevTypes011[] = "DT..W..OMCA.BK";
+static char SenseDevTypes012[] = "..............";
+static char SenseDevTypes013[] = "DTL.WRSOMCAEBK";
+static char SenseDevTypes014[] = "DTL.WRSOM...BK";
+static char SenseDevTypes015[] = "DT...R.OM...BK";
+static char SenseDevTypes016[] = "DTLPWRSO.C...K";
+static char SenseDevTypes017[] = "DT..WR.O....B.";
+static char SenseDevTypes018[] = "....WR.O.....K";
+static char SenseDevTypes019[] = "....WR.O......";
+static char SenseDevTypes020[] = ".T...RS.......";
+static char SenseDevTypes021[] = ".............K";
+static char SenseDevTypes022[] = "DT..W..O....B.";
+static char SenseDevTypes023[] = "DT..WRSO....BK";
+static char SenseDevTypes024[] = "DT..W.SO....BK";
+static char SenseDevTypes025[] = "....WR.O....B.";
+static char SenseDevTypes026[] = "....W..O....B.";
+static char SenseDevTypes027[] = "DT.....O....BK";
+static char SenseDevTypes028[] = "DTL.WRSO....BK";
+static char SenseDevTypes029[] = "DT..WR.O....BK";
+static char SenseDevTypes030[] = "DT..W..O....BK";
+static char SenseDevTypes031[] = "D...WR.O....BK";
+static char SenseDevTypes032[] = "D......O.....K";
+static char SenseDevTypes033[] = "D......O....BK";
+static char SenseDevTypes034[] = "DT..WR.OM...BK";
+static char SenseDevTypes035[] = "D.............";
+static char SenseDevTypes036[] = "DTLPWRSOMCAE.K";
+static char SenseDevTypes037[] = "DTLPWRSOMCA.BK";
+static char SenseDevTypes038[] = ".T...R........";
+static char SenseDevTypes039[] = "DT..WR.OM...B.";
+static char SenseDevTypes040[] = "DTL.WRSOMCAE.K";
+static char SenseDevTypes041[] = "DTLPWRSOMCAE..";
+static char SenseDevTypes042[] = "......S.......";
+static char SenseDevTypes043[] = "............B.";
+static char SenseDevTypes044[] = "DTLPWRSO.CA..K";
+static char SenseDevTypes045[] = "DT...R.......K";
+static char SenseDevTypes046[] = "D.L..R.O....B.";
+static char SenseDevTypes047[] = "..L...........";
+static char SenseDevTypes048[] = ".TL...........";
+static char SenseDevTypes049[] = "DTLPWRSOMC..BK";
+static char SenseDevTypes050[] = "DT..WR.OMCAEBK";
+static char SenseDevTypes051[] = "DT..WR.OMCAEB.";
+static char SenseDevTypes052[] = ".T...R.O......";
+static char SenseDevTypes053[] = "...P..........";
+static char SenseDevTypes054[] = "DTLPWRSOM.AE.K";
+static char SenseDevTypes055[] = "DTLPWRSOM.AE..";
+static char SenseDevTypes056[] = ".......O......";
+static char SenseDevTypes057[] = "DTLPWRSOM...BK";
+static char SenseDevTypes058[] = "DT..WR.O..A.BK";
+static char SenseDevTypes059[] = "DTLPWRSOM....K";
+static char SenseDevTypes060[] = "D......O......";
+static char SenseDevTypes061[] = ".....R......B.";
+static char SenseDevTypes062[] = "D...........B.";
+static char SenseDevTypes063[] = "............BK";
+static char SenseDevTypes064[] = "..........A...";
+
+static ASCQ_Table_t ASCQ_Table[] = {
+  {
+    0x00, 0x00,
+    SenseDevTypes001,
+    "NO ADDITIONAL SENSE INFORMATION"
+  },
+  {
+    0x00, 0x01,
+    SenseDevTypes002,
+    "FILEMARK DETECTED"
+  },
+  {
+    0x00, 0x02,
+    SenseDevTypes003,
+    "END-OF-PARTITION/MEDIUM DETECTED"
+  },
+  {
+    0x00, 0x03,
+    SenseDevTypes002,
+    "SETMARK DETECTED"
+  },
+  {
+    0x00, 0x04,
+    SenseDevTypes003,
+    "BEGINNING-OF-PARTITION/MEDIUM DETECTED"
+  },
+  {
+    0x00, 0x05,
+    SenseDevTypes004,
+    "END-OF-DATA DETECTED"
+  },
+  {
+    0x00, 0x06,
+    SenseDevTypes001,
+    "I/O PROCESS TERMINATED"
+  },
+  {
+    0x00, 0x11,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION IN PROGRESS"
+  },
+  {
+    0x00, 0x12,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION PAUSED"
+  },
+  {
+    0x00, 0x13,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"
+  },
+  {
+    0x00, 0x14,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"
+  },
+  {
+    0x00, 0x15,
+    SenseDevTypes005,
+    "NO CURRENT AUDIO STATUS TO RETURN"
+  },
+  {
+    0x00, 0x16,
+    SenseDevTypes001,
+    "OPERATION IN PROGRESS"
+  },
+  {
+    0x00, 0x17,
+    SenseDevTypes006,
+    "CLEANING REQUESTED"
+  },
+  {
+    0x01, 0x00,
+    SenseDevTypes007,
+    "NO INDEX/SECTOR SIGNAL"
+  },
+  {
+    0x02, 0x00,
+    SenseDevTypes008,
+    "NO SEEK COMPLETE"
+  },
+  {
+    0x03, 0x00,
+    SenseDevTypes009,
+    "PERIPHERAL DEVICE WRITE FAULT"
+  },
+  {
+    0x03, 0x01,
+    SenseDevTypes002,
+    "NO WRITE CURRENT"
+  },
+  {
+    0x03, 0x02,
+    SenseDevTypes002,
+    "EXCESSIVE WRITE ERRORS"
+  },
+  {
+    0x04, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"
+  },
+  {
+    0x04, 0x01,
+    SenseDevTypes001,
+    "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"
+  },
+  {
+    0x04, 0x02,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED"
+  },
+  {
+    0x04, 0x03,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"
+  },
+  {
+    0x04, 0x04,
+    SenseDevTypes010,
+    "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"
+  },
+  {
+    0x04, 0x05,
+    SenseDevTypes011,
+    "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"
+  },
+  {
+    0x04, 0x06,
+    SenseDevTypes011,
+    "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"
+  },
+  {
+    0x04, 0x07,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"
+  },
+  {
+    0x04, 0x08,
+    SenseDevTypes005,
+    "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"
+  },
+  {
+    0x04, 0x09,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS"
+  },
+  {
+    0x04, 0x10,
+    SenseDevTypes012,
+    "auxiliary memory code 2 (99-148) [proposed]"
+  },
+  {
+    0x05, 0x00,
+    SenseDevTypes013,
+    "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"
+  },
+  {
+    0x06, 0x00,
+    SenseDevTypes008,
+    "NO REFERENCE POSITION FOUND"
+  },
+  {
+    0x07, 0x00,
+    SenseDevTypes014,
+    "MULTIPLE PERIPHERAL DEVICES SELECTED"
+  },
+  {
+    0x08, 0x00,
+    SenseDevTypes013,
+    "LOGICAL UNIT COMMUNICATION FAILURE"
+  },
+  {
+    0x08, 0x01,
+    SenseDevTypes013,
+    "LOGICAL UNIT COMMUNICATION TIME-OUT"
+  },
+  {
+    0x08, 0x02,
+    SenseDevTypes013,
+    "LOGICAL UNIT COMMUNICATION PARITY ERROR"
+  },
+  {
+    0x08, 0x03,
+    SenseDevTypes015,
+    "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)"
+  },
+  {
+    0x08, 0x04,
+    SenseDevTypes016,
+    "UNREACHABLE COPY TARGET"
+  },
+  {
+    0x09, 0x00,
+    SenseDevTypes017,
+    "TRACK FOLLOWING ERROR"
+  },
+  {
+    0x09, 0x01,
+    SenseDevTypes018,
+    "TRACKING SERVO FAILURE"
+  },
+  {
+    0x09, 0x02,
+    SenseDevTypes018,
+    "FOCUS SERVO FAILURE"
+  },
+  {
+    0x09, 0x03,
+    SenseDevTypes019,
+    "SPINDLE SERVO FAILURE"
+  },
+  {
+    0x09, 0x04,
+    SenseDevTypes017,
+    "HEAD SELECT FAULT"
+  },
+  {
+    0x0A, 0x00,
+    SenseDevTypes001,
+    "ERROR LOG OVERFLOW"
+  },
+  {
+    0x0B, 0x00,
+    SenseDevTypes001,
+    "WARNING"
+  },
+  {
+    0x0B, 0x01,
+    SenseDevTypes001,
+    "WARNING - SPECIFIED TEMPERATURE EXCEEDED"
+  },
+  {
+    0x0B, 0x02,
+    SenseDevTypes001,
+    "WARNING - ENCLOSURE DEGRADED"
+  },
+  {
+    0x0C, 0x00,
+    SenseDevTypes020,
+    "WRITE ERROR"
+  },
+  {
+    0x0C, 0x01,
+    SenseDevTypes021,
+    "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"
+  },
+  {
+    0x0C, 0x02,
+    SenseDevTypes007,
+    "WRITE ERROR - AUTO REALLOCATION FAILED"
+  },
+  {
+    0x0C, 0x03,
+    SenseDevTypes007,
+    "WRITE ERROR - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x0C, 0x04,
+    SenseDevTypes022,
+    "COMPRESSION CHECK MISCOMPARE ERROR"
+  },
+  {
+    0x0C, 0x05,
+    SenseDevTypes022,
+    "DATA EXPANSION OCCURRED DURING COMPRESSION"
+  },
+  {
+    0x0C, 0x06,
+    SenseDevTypes022,
+    "BLOCK NOT COMPRESSIBLE"
+  },
+  {
+    0x0C, 0x07,
+    SenseDevTypes005,
+    "WRITE ERROR - RECOVERY NEEDED"
+  },
+  {
+    0x0C, 0x08,
+    SenseDevTypes005,
+    "WRITE ERROR - RECOVERY FAILED"
+  },
+  {
+    0x0C, 0x09,
+    SenseDevTypes005,
+    "WRITE ERROR - LOSS OF STREAMING"
+  },
+  {
+    0x0C, 0x0A,
+    SenseDevTypes005,
+    "WRITE ERROR - PADDING BLOCKS ADDED"
+  },
+  {
+    0x0C, 0x0B,
+    SenseDevTypes012,
+    "auxiliary memory code 4 (99-148) [proposed]"
+  },
+  {
+    0x10, 0x00,
+    SenseDevTypes007,
+    "ID CRC OR ECC ERROR"
+  },
+  {
+    0x11, 0x00,
+    SenseDevTypes023,
+    "UNRECOVERED READ ERROR"
+  },
+  {
+    0x11, 0x01,
+    SenseDevTypes023,
+    "READ RETRIES EXHAUSTED"
+  },
+  {
+    0x11, 0x02,
+    SenseDevTypes023,
+    "ERROR TOO LONG TO CORRECT"
+  },
+  {
+    0x11, 0x03,
+    SenseDevTypes024,
+    "MULTIPLE READ ERRORS"
+  },
+  {
+    0x11, 0x04,
+    SenseDevTypes007,
+    "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"
+  },
+  {
+    0x11, 0x05,
+    SenseDevTypes025,
+    "L-EC UNCORRECTABLE ERROR"
+  },
+  {
+    0x11, 0x06,
+    SenseDevTypes025,
+    "CIRC UNRECOVERED ERROR"
+  },
+  {
+    0x11, 0x07,
+    SenseDevTypes026,
+    "DATA RE-SYNCHRONIZATION ERROR"
+  },
+  {
+    0x11, 0x08,
+    SenseDevTypes002,
+    "INCOMPLETE BLOCK READ"
+  },
+  {
+    0x11, 0x09,
+    SenseDevTypes002,
+    "NO GAP FOUND"
+  },
+  {
+    0x11, 0x0A,
+    SenseDevTypes027,
+    "MISCORRECTED ERROR"
+  },
+  {
+    0x11, 0x0B,
+    SenseDevTypes007,
+    "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x11, 0x0C,
+    SenseDevTypes007,
+    "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA"
+  },
+  {
+    0x11, 0x0D,
+    SenseDevTypes017,
+    "DE-COMPRESSION CRC ERROR"
+  },
+  {
+    0x11, 0x0E,
+    SenseDevTypes017,
+    "CANNOT DECOMPRESS USING DECLARED ALGORITHM"
+  },
+  {
+    0x11, 0x0F,
+    SenseDevTypes005,
+    "ERROR READING UPC/EAN NUMBER"
+  },
+  {
+    0x11, 0x10,
+    SenseDevTypes005,
+    "ERROR READING ISRC NUMBER"
+  },
+  {
+    0x11, 0x11,
+    SenseDevTypes005,
+    "READ ERROR - LOSS OF STREAMING"
+  },
+  {
+    0x11, 0x12,
+    SenseDevTypes012,
+    "auxiliary memory code 3 (99-148) [proposed]"
+  },
+  {
+    0x12, 0x00,
+    SenseDevTypes007,
+    "ADDRESS MARK NOT FOUND FOR ID FIELD"
+  },
+  {
+    0x13, 0x00,
+    SenseDevTypes007,
+    "ADDRESS MARK NOT FOUND FOR DATA FIELD"
+  },
+  {
+    0x14, 0x00,
+    SenseDevTypes028,
+    "RECORDED ENTITY NOT FOUND"
+  },
+  {
+    0x14, 0x01,
+    SenseDevTypes029,
+    "RECORD NOT FOUND"
+  },
+  {
+    0x14, 0x02,
+    SenseDevTypes002,
+    "FILEMARK OR SETMARK NOT FOUND"
+  },
+  {
+    0x14, 0x03,
+    SenseDevTypes002,
+    "END-OF-DATA NOT FOUND"
+  },
+  {
+    0x14, 0x04,
+    SenseDevTypes002,
+    "BLOCK SEQUENCE ERROR"
+  },
+  {
+    0x14, 0x05,
+    SenseDevTypes030,
+    "RECORD NOT FOUND - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x14, 0x06,
+    SenseDevTypes030,
+    "RECORD NOT FOUND - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x15, 0x00,
+    SenseDevTypes014,
+    "RANDOM POSITIONING ERROR"
+  },
+  {
+    0x15, 0x01,
+    SenseDevTypes014,
+    "MECHANICAL POSITIONING ERROR"
+  },
+  {
+    0x15, 0x02,
+    SenseDevTypes029,
+    "POSITIONING ERROR DETECTED BY READ OF MEDIUM"
+  },
+  {
+    0x16, 0x00,
+    SenseDevTypes007,
+    "DATA SYNCHRONIZATION MARK ERROR"
+  },
+  {
+    0x16, 0x01,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - DATA REWRITTEN"
+  },
+  {
+    0x16, 0x02,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - RECOMMEND REWRITE"
+  },
+  {
+    0x16, 0x03,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x16, 0x04,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x17, 0x00,
+    SenseDevTypes023,
+    "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"
+  },
+  {
+    0x17, 0x01,
+    SenseDevTypes023,
+    "RECOVERED DATA WITH RETRIES"
+  },
+  {
+    0x17, 0x02,
+    SenseDevTypes029,
+    "RECOVERED DATA WITH POSITIVE HEAD OFFSET"
+  },
+  {
+    0x17, 0x03,
+    SenseDevTypes029,
+    "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"
+  },
+  {
+    0x17, 0x04,
+    SenseDevTypes025,
+    "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"
+  },
+  {
+    0x17, 0x05,
+    SenseDevTypes031,
+    "RECOVERED DATA USING PREVIOUS SECTOR ID"
+  },
+  {
+    0x17, 0x06,
+    SenseDevTypes007,
+    "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x17, 0x07,
+    SenseDevTypes031,
+    "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x17, 0x08,
+    SenseDevTypes031,
+    "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE"
+  },
+  {
+    0x17, 0x09,
+    SenseDevTypes031,
+    "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"
+  },
+  {
+    0x18, 0x00,
+    SenseDevTypes029,
+    "RECOVERED DATA WITH ERROR CORRECTION APPLIED"
+  },
+  {
+    0x18, 0x01,
+    SenseDevTypes031,
+    "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED"
+  },
+  {
+    0x18, 0x02,
+    SenseDevTypes031,
+    "RECOVERED DATA - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x18, 0x03,
+    SenseDevTypes005,
+    "RECOVERED DATA WITH CIRC"
+  },
+  {
+    0x18, 0x04,
+    SenseDevTypes005,
+    "RECOVERED DATA WITH L-EC"
+  },
+  {
+    0x18, 0x05,
+    SenseDevTypes031,
+    "RECOVERED DATA - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x18, 0x06,
+    SenseDevTypes031,
+    "RECOVERED DATA - RECOMMEND REWRITE"
+  },
+  {
+    0x18, 0x07,
+    SenseDevTypes007,
+    "RECOVERED DATA WITH ECC - DATA REWRITTEN"
+  },
+  {
+    0x19, 0x00,
+    SenseDevTypes032,
+    "DEFECT LIST ERROR"
+  },
+  {
+    0x19, 0x01,
+    SenseDevTypes032,
+    "DEFECT LIST NOT AVAILABLE"
+  },
+  {
+    0x19, 0x02,
+    SenseDevTypes032,
+    "DEFECT LIST ERROR IN PRIMARY LIST"
+  },
+  {
+    0x19, 0x03,
+    SenseDevTypes032,
+    "DEFECT LIST ERROR IN GROWN LIST"
+  },
+  {
+    0x1A, 0x00,
+    SenseDevTypes001,
+    "PARAMETER LIST LENGTH ERROR"
+  },
+  {
+    0x1B, 0x00,
+    SenseDevTypes001,
+    "SYNCHRONOUS DATA TRANSFER ERROR"
+  },
+  {
+    0x1C, 0x00,
+    SenseDevTypes033,
+    "DEFECT LIST NOT FOUND"
+  },
+  {
+    0x1C, 0x01,
+    SenseDevTypes033,
+    "PRIMARY DEFECT LIST NOT FOUND"
+  },
+  {
+    0x1C, 0x02,
+    SenseDevTypes033,
+    "GROWN DEFECT LIST NOT FOUND"
+  },
+  {
+    0x1D, 0x00,
+    SenseDevTypes029,
+    "MISCOMPARE DURING VERIFY OPERATION"
+  },
+  {
+    0x1E, 0x00,
+    SenseDevTypes007,
+    "RECOVERED ID WITH ECC CORRECTION"
+  },
+  {
+    0x1F, 0x00,
+    SenseDevTypes032,
+    "PARTIAL DEFECT LIST TRANSFER"
+  },
+  {
+    0x20, 0x00,
+    SenseDevTypes001,
+    "INVALID COMMAND OPERATION CODE"
+  },
+  {
+    0x20, 0x01,
+    SenseDevTypes012,
+    "access controls code 1 (99-314) [proposed]"
+  },
+  {
+    0x20, 0x02,
+    SenseDevTypes012,
+    "access controls code 2 (99-314) [proposed]"
+  },
+  {
+    0x20, 0x03,
+    SenseDevTypes012,
+    "access controls code 3 (99-314) [proposed]"
+  },
+  {
+    0x21, 0x00,
+    SenseDevTypes034,
+    "LOGICAL BLOCK ADDRESS OUT OF RANGE"
+  },
+  {
+    0x21, 0x01,
+    SenseDevTypes034,
+    "INVALID ELEMENT ADDRESS"
+  },
+  {
+    0x22, 0x00,
+    SenseDevTypes035,
+    "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)"
+  },
+  {
+    0x24, 0x00,
+    SenseDevTypes001,
+    "INVALID FIELD IN CDB"
+  },
+  {
+    0x24, 0x01,
+    SenseDevTypes001,
+    "CDB DECRYPTION ERROR"
+  },
+  {
+    0x25, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT SUPPORTED"
+  },
+  {
+    0x26, 0x00,
+    SenseDevTypes001,
+    "INVALID FIELD IN PARAMETER LIST"
+  },
+  {
+    0x26, 0x01,
+    SenseDevTypes001,
+    "PARAMETER NOT SUPPORTED"
+  },
+  {
+    0x26, 0x02,
+    SenseDevTypes001,
+    "PARAMETER VALUE INVALID"
+  },
+  {
+    0x26, 0x03,
+    SenseDevTypes036,
+    "THRESHOLD PARAMETERS NOT SUPPORTED"
+  },
+  {
+    0x26, 0x04,
+    SenseDevTypes001,
+    "INVALID RELEASE OF PERSISTENT RESERVATION"
+  },
+  {
+    0x26, 0x05,
+    SenseDevTypes037,
+    "DATA DECRYPTION ERROR"
+  },
+  {
+    0x26, 0x06,
+    SenseDevTypes016,
+    "TOO MANY TARGET DESCRIPTORS"
+  },
+  {
+    0x26, 0x07,
+    SenseDevTypes016,
+    "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE"
+  },
+  {
+    0x26, 0x08,
+    SenseDevTypes016,
+    "TOO MANY SEGMENT DESCRIPTORS"
+  },
+  {
+    0x26, 0x09,
+    SenseDevTypes016,
+    "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE"
+  },
+  {
+    0x26, 0x0A,
+    SenseDevTypes016,
+    "UNEXPECTED INEXACT SEGMENT"
+  },
+  {
+    0x26, 0x0B,
+    SenseDevTypes016,
+    "INLINE DATA LENGTH EXCEEDED"
+  },
+  {
+    0x26, 0x0C,
+    SenseDevTypes016,
+    "INVALID OPERATION FOR COPY SOURCE OR DESTINATION"
+  },
+  {
+    0x26, 0x0D,
+    SenseDevTypes016,
+    "COPY SEGMENT GRANULARITY VIOLATION"
+  },
+  {
+    0x27, 0x00,
+    SenseDevTypes029,
+    "WRITE PROTECTED"
+  },
+  {
+    0x27, 0x01,
+    SenseDevTypes029,
+    "HARDWARE WRITE PROTECTED"
+  },
+  {
+    0x27, 0x02,
+    SenseDevTypes029,
+    "LOGICAL UNIT SOFTWARE WRITE PROTECTED"
+  },
+  {
+    0x27, 0x03,
+    SenseDevTypes038,
+    "ASSOCIATED WRITE PROTECT"
+  },
+  {
+    0x27, 0x04,
+    SenseDevTypes038,
+    "PERSISTENT WRITE PROTECT"
+  },
+  {
+    0x27, 0x05,
+    SenseDevTypes038,
+    "PERMANENT WRITE PROTECT"
+  },
+  {
+    0x28, 0x00,
+    SenseDevTypes001,
+    "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED"
+  },
+  {
+    0x28, 0x01,
+    SenseDevTypes039,
+    "IMPORT OR EXPORT ELEMENT ACCESSED"
+  },
+  {
+    0x29, 0x00,
+    SenseDevTypes001,
+    "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  },
+  {
+    0x29, 0x01,
+    SenseDevTypes001,
+    "POWER ON OCCURRED"
+  },
+  {
+    0x29, 0x02,
+    SenseDevTypes001,
+    "SCSI BUS RESET OCCURRED"
+  },
+  {
+    0x29, 0x03,
+    SenseDevTypes001,
+    "BUS DEVICE RESET FUNCTION OCCURRED"
+  },
+  {
+    0x29, 0x04,
+    SenseDevTypes001,
+    "DEVICE INTERNAL RESET"
+  },
+  {
+    0x29, 0x05,
+    SenseDevTypes001,
+    "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED"
+  },
+  {
+    0x29, 0x06,
+    SenseDevTypes001,
+    "TRANSCEIVER MODE CHANGED TO LVD"
+  },
+  {
+    0x2A, 0x00,
+    SenseDevTypes013,
+    "PARAMETERS CHANGED"
+  },
+  {
+    0x2A, 0x01,
+    SenseDevTypes013,
+    "MODE PARAMETERS CHANGED"
+  },
+  {
+    0x2A, 0x02,
+    SenseDevTypes040,
+    "LOG PARAMETERS CHANGED"
+  },
+  {
+    0x2A, 0x03,
+    SenseDevTypes036,
+    "RESERVATIONS PREEMPTED"
+  },
+  {
+    0x2A, 0x04,
+    SenseDevTypes041,
+    "RESERVATIONS RELEASED"
+  },
+  {
+    0x2A, 0x05,
+    SenseDevTypes041,
+    "REGISTRATIONS PREEMPTED"
+  },
+  {
+    0x2B, 0x00,
+    SenseDevTypes016,
+    "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"
+  },
+  {
+    0x2C, 0x00,
+    SenseDevTypes001,
+    "COMMAND SEQUENCE ERROR"
+  },
+  {
+    0x2C, 0x01,
+    SenseDevTypes042,
+    "TOO MANY WINDOWS SPECIFIED"
+  },
+  {
+    0x2C, 0x02,
+    SenseDevTypes042,
+    "INVALID COMBINATION OF WINDOWS SPECIFIED"
+  },
+  {
+    0x2C, 0x03,
+    SenseDevTypes005,
+    "CURRENT PROGRAM AREA IS NOT EMPTY"
+  },
+  {
+    0x2C, 0x04,
+    SenseDevTypes005,
+    "CURRENT PROGRAM AREA IS EMPTY"
+  },
+  {
+    0x2C, 0x05,
+    SenseDevTypes043,
+    "ILLEGAL POWER CONDITION REQUEST"
+  },
+  {
+    0x2D, 0x00,
+    SenseDevTypes002,
+    "OVERWRITE ERROR ON UPDATE IN PLACE"
+  },
+  {
+    0x2E, 0x00,
+    SenseDevTypes044,
+    "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR"
+  },
+  {
+    0x2E, 0x01,
+    SenseDevTypes044,
+    "THIRD PARTY DEVICE FAILURE"
+  },
+  {
+    0x2E, 0x02,
+    SenseDevTypes044,
+    "COPY TARGET DEVICE NOT REACHABLE"
+  },
+  {
+    0x2E, 0x03,
+    SenseDevTypes044,
+    "INCORRECT COPY TARGET DEVICE TYPE"
+  },
+  {
+    0x2E, 0x04,
+    SenseDevTypes044,
+    "COPY TARGET DEVICE DATA UNDERRUN"
+  },
+  {
+    0x2E, 0x05,
+    SenseDevTypes044,
+    "COPY TARGET DEVICE DATA OVERRUN"
+  },
+  {
+    0x2F, 0x00,
+    SenseDevTypes001,
+    "COMMANDS CLEARED BY ANOTHER INITIATOR"
+  },
+  {
+    0x30, 0x00,
+    SenseDevTypes034,
+    "INCOMPATIBLE MEDIUM INSTALLED"
+  },
+  {
+    0x30, 0x01,
+    SenseDevTypes029,
+    "CANNOT READ MEDIUM - UNKNOWN FORMAT"
+  },
+  {
+    0x30, 0x02,
+    SenseDevTypes029,
+    "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"
+  },
+  {
+    0x30, 0x03,
+    SenseDevTypes045,
+    "CLEANING CARTRIDGE INSTALLED"
+  },
+  {
+    0x30, 0x04,
+    SenseDevTypes029,
+    "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"
+  },
+  {
+    0x30, 0x05,
+    SenseDevTypes029,
+    "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"
+  },
+  {
+    0x30, 0x06,
+    SenseDevTypes017,
+    "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"
+  },
+  {
+    0x30, 0x07,
+    SenseDevTypes006,
+    "CLEANING FAILURE"
+  },
+  {
+    0x30, 0x08,
+    SenseDevTypes005,
+    "CANNOT WRITE - APPLICATION CODE MISMATCH"
+  },
+  {
+    0x30, 0x09,
+    SenseDevTypes005,
+    "CURRENT SESSION NOT FIXATED FOR APPEND"
+  },
+  {
+    0x31, 0x00,
+    SenseDevTypes029,
+    "MEDIUM FORMAT CORRUPTED"
+  },
+  {
+    0x31, 0x01,
+    SenseDevTypes046,
+    "FORMAT COMMAND FAILED"
+  },
+  {
+    0x32, 0x00,
+    SenseDevTypes007,
+    "NO DEFECT SPARE LOCATION AVAILABLE"
+  },
+  {
+    0x32, 0x01,
+    SenseDevTypes007,
+    "DEFECT LIST UPDATE FAILURE"
+  },
+  {
+    0x33, 0x00,
+    SenseDevTypes002,
+    "TAPE LENGTH ERROR"
+  },
+  {
+    0x34, 0x00,
+    SenseDevTypes001,
+    "ENCLOSURE FAILURE"
+  },
+  {
+    0x35, 0x00,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES FAILURE"
+  },
+  {
+    0x35, 0x01,
+    SenseDevTypes001,
+    "UNSUPPORTED ENCLOSURE FUNCTION"
+  },
+  {
+    0x35, 0x02,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES UNAVAILABLE"
+  },
+  {
+    0x35, 0x03,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES TRANSFER FAILURE"
+  },
+  {
+    0x35, 0x04,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES TRANSFER REFUSED"
+  },
+  {
+    0x36, 0x00,
+    SenseDevTypes047,
+    "RIBBON, INK, OR TONER FAILURE"
+  },
+  {
+    0x37, 0x00,
+    SenseDevTypes013,
+    "ROUNDED PARAMETER"
+  },
+  {
+    0x38, 0x00,
+    SenseDevTypes043,
+    "EVENT STATUS NOTIFICATION"
+  },
+  {
+    0x38, 0x02,
+    SenseDevTypes043,
+    "ESN - POWER MANAGEMENT CLASS EVENT"
+  },
+  {
+    0x38, 0x04,
+    SenseDevTypes043,
+    "ESN - MEDIA CLASS EVENT"
+  },
+  {
+    0x38, 0x06,
+    SenseDevTypes043,
+    "ESN - DEVICE BUSY CLASS EVENT"
+  },
+  {
+    0x39, 0x00,
+    SenseDevTypes040,
+    "SAVING PARAMETERS NOT SUPPORTED"
+  },
+  {
+    0x3A, 0x00,
+    SenseDevTypes014,
+    "MEDIUM NOT PRESENT"
+  },
+  {
+    0x3A, 0x01,
+    SenseDevTypes034,
+    "MEDIUM NOT PRESENT - TRAY CLOSED"
+  },
+  {
+    0x3A, 0x02,
+    SenseDevTypes034,
+    "MEDIUM NOT PRESENT - TRAY OPEN"
+  },
+  {
+    0x3A, 0x03,
+    SenseDevTypes039,
+    "MEDIUM NOT PRESENT - LOADABLE"
+  },
+  {
+    0x3A, 0x04,
+    SenseDevTypes039,
+    "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE"
+  },
+  {
+    0x3B, 0x00,
+    SenseDevTypes048,
+    "SEQUENTIAL POSITIONING ERROR"
+  },
+  {
+    0x3B, 0x01,
+    SenseDevTypes002,
+    "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"
+  },
+  {
+    0x3B, 0x02,
+    SenseDevTypes002,
+    "TAPE POSITION ERROR AT END-OF-MEDIUM"
+  },
+  {
+    0x3B, 0x03,
+    SenseDevTypes047,
+    "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"
+  },
+  {
+    0x3B, 0x04,
+    SenseDevTypes047,
+    "SLEW FAILURE"
+  },
+  {
+    0x3B, 0x05,
+    SenseDevTypes047,
+    "PAPER JAM"
+  },
+  {
+    0x3B, 0x06,
+    SenseDevTypes047,
+    "FAILED TO SENSE TOP-OF-FORM"
+  },
+  {
+    0x3B, 0x07,
+    SenseDevTypes047,
+    "FAILED TO SENSE BOTTOM-OF-FORM"
+  },
+  {
+    0x3B, 0x08,
+    SenseDevTypes002,
+    "REPOSITION ERROR"
+  },
+  {
+    0x3B, 0x09,
+    SenseDevTypes042,
+    "READ PAST END OF MEDIUM"
+  },
+  {
+    0x3B, 0x0A,
+    SenseDevTypes042,
+    "READ PAST BEGINNING OF MEDIUM"
+  },
+  {
+    0x3B, 0x0B,
+    SenseDevTypes042,
+    "POSITION PAST END OF MEDIUM"
+  },
+  {
+    0x3B, 0x0C,
+    SenseDevTypes003,
+    "POSITION PAST BEGINNING OF MEDIUM"
+  },
+  {
+    0x3B, 0x0D,
+    SenseDevTypes034,
+    "MEDIUM DESTINATION ELEMENT FULL"
+  },
+  {
+    0x3B, 0x0E,
+    SenseDevTypes034,
+    "MEDIUM SOURCE ELEMENT EMPTY"
+  },
+  {
+    0x3B, 0x0F,
+    SenseDevTypes005,
+    "END OF MEDIUM REACHED"
+  },
+  {
+    0x3B, 0x11,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE NOT ACCESSIBLE"
+  },
+  {
+    0x3B, 0x12,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE REMOVED"
+  },
+  {
+    0x3B, 0x13,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE INSERTED"
+  },
+  {
+    0x3B, 0x14,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE LOCKED"
+  },
+  {
+    0x3B, 0x15,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE UNLOCKED"
+  },
+  {
+    0x3B, 0x16,
+    SenseDevTypes005,
+    "MECHANICAL POSITIONING OR CHANGER ERROR"
+  },
+  {
+    0x3D, 0x00,
+    SenseDevTypes036,
+    "INVALID BITS IN IDENTIFY MESSAGE"
+  },
+  {
+    0x3E, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"
+  },
+  {
+    0x3E, 0x01,
+    SenseDevTypes001,
+    "LOGICAL UNIT FAILURE"
+  },
+  {
+    0x3E, 0x02,
+    SenseDevTypes001,
+    "TIMEOUT ON LOGICAL UNIT"
+  },
+  {
+    0x3E, 0x03,
+    SenseDevTypes001,
+    "LOGICAL UNIT FAILED SELF-TEST"
+  },
+  {
+    0x3E, 0x04,
+    SenseDevTypes001,
+    "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG"
+  },
+  {
+    0x3F, 0x00,
+    SenseDevTypes001,
+    "TARGET OPERATING CONDITIONS HAVE CHANGED"
+  },
+  {
+    0x3F, 0x01,
+    SenseDevTypes001,
+    "MICROCODE HAS BEEN CHANGED"
+  },
+  {
+    0x3F, 0x02,
+    SenseDevTypes049,
+    "CHANGED OPERATING DEFINITION"
+  },
+  {
+    0x3F, 0x03,
+    SenseDevTypes001,
+    "INQUIRY DATA HAS CHANGED"
+  },
+  {
+    0x3F, 0x04,
+    SenseDevTypes050,
+    "COMPONENT DEVICE ATTACHED"
+  },
+  {
+    0x3F, 0x05,
+    SenseDevTypes050,
+    "DEVICE IDENTIFIER CHANGED"
+  },
+  {
+    0x3F, 0x06,
+    SenseDevTypes051,
+    "REDUNDANCY GROUP CREATED OR MODIFIED"
+  },
+  {
+    0x3F, 0x07,
+    SenseDevTypes051,
+    "REDUNDANCY GROUP DELETED"
+  },
+  {
+    0x3F, 0x08,
+    SenseDevTypes051,
+    "SPARE CREATED OR MODIFIED"
+  },
+  {
+    0x3F, 0x09,
+    SenseDevTypes051,
+    "SPARE DELETED"
+  },
+  {
+    0x3F, 0x0A,
+    SenseDevTypes050,
+    "VOLUME SET CREATED OR MODIFIED"
+  },
+  {
+    0x3F, 0x0B,
+    SenseDevTypes050,
+    "VOLUME SET DELETED"
+  },
+  {
+    0x3F, 0x0C,
+    SenseDevTypes050,
+    "VOLUME SET DEASSIGNED"
+  },
+  {
+    0x3F, 0x0D,
+    SenseDevTypes050,
+    "VOLUME SET REASSIGNED"
+  },
+  {
+    0x3F, 0x0E,
+    SenseDevTypes041,
+    "REPORTED LUNS DATA HAS CHANGED"
+  },
+  {
+    0x3F, 0x0F,
+    SenseDevTypes001,
+    "ECHO BUFFER OVERWRITTEN"
+  },
+  {
+    0x3F, 0x10,
+    SenseDevTypes039,
+    "MEDIUM LOADABLE"
+  },
+  {
+    0x3F, 0x11,
+    SenseDevTypes039,
+    "MEDIUM AUXILIARY MEMORY ACCESSIBLE"
+  },
+  {
+    0x40, 0x00,
+    SenseDevTypes035,
+    "RAM FAILURE (SHOULD USE 40 NN)"
+  },
+  {
+    0x40, 0xFF,
+    SenseDevTypes001,
+    "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)"
+  },
+  {
+    0x41, 0x00,
+    SenseDevTypes035,
+    "DATA PATH FAILURE (SHOULD USE 40 NN)"
+  },
+  {
+    0x42, 0x00,
+    SenseDevTypes035,
+    "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)"
+  },
+  {
+    0x43, 0x00,
+    SenseDevTypes001,
+    "MESSAGE ERROR"
+  },
+  {
+    0x44, 0x00,
+    SenseDevTypes001,
+    "INTERNAL TARGET FAILURE"
+  },
+  {
+    0x45, 0x00,
+    SenseDevTypes001,
+    "SELECT OR RESELECT FAILURE"
+  },
+  {
+    0x46, 0x00,
+    SenseDevTypes049,
+    "UNSUCCESSFUL SOFT RESET"
+  },
+  {
+    0x47, 0x00,
+    SenseDevTypes001,
+    "SCSI PARITY ERROR"
+  },
+  {
+    0x47, 0x01,
+    SenseDevTypes001,
+    "DATA PHASE CRC ERROR DETECTED"
+  },
+  {
+    0x47, 0x02,
+    SenseDevTypes001,
+    "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE"
+  },
+  {
+    0x47, 0x03,
+    SenseDevTypes001,
+    "INFORMATION UNIT CRC ERROR DETECTED"
+  },
+  {
+    0x47, 0x04,
+    SenseDevTypes001,
+    "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED"
+  },
+  {
+    0x48, 0x00,
+    SenseDevTypes001,
+    "INITIATOR DETECTED ERROR MESSAGE RECEIVED"
+  },
+  {
+    0x49, 0x00,
+    SenseDevTypes001,
+    "INVALID MESSAGE ERROR"
+  },
+  {
+    0x4A, 0x00,
+    SenseDevTypes001,
+    "COMMAND PHASE ERROR"
+  },
+  {
+    0x4B, 0x00,
+    SenseDevTypes001,
+    "DATA PHASE ERROR"
+  },
+  {
+    0x4C, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT FAILED SELF-CONFIGURATION"
+  },
+  {
+    0x4D, 0xFF,
+    SenseDevTypes001,
+    "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)"
+  },
+  {
+    0x4E, 0x00,
+    SenseDevTypes001,
+    "OVERLAPPED COMMANDS ATTEMPTED"
+  },
+  {
+    0x50, 0x00,
+    SenseDevTypes002,
+    "WRITE APPEND ERROR"
+  },
+  {
+    0x50, 0x01,
+    SenseDevTypes002,
+    "WRITE APPEND POSITION ERROR"
+  },
+  {
+    0x50, 0x02,
+    SenseDevTypes002,
+    "POSITION ERROR RELATED TO TIMING"
+  },
+  {
+    0x51, 0x00,
+    SenseDevTypes052,
+    "ERASE FAILURE"
+  },
+  {
+    0x52, 0x00,
+    SenseDevTypes002,
+    "CARTRIDGE FAULT"
+  },
+  {
+    0x53, 0x00,
+    SenseDevTypes014,
+    "MEDIA LOAD OR EJECT FAILED"
+  },
+  {
+    0x53, 0x01,
+    SenseDevTypes002,
+    "UNLOAD TAPE FAILURE"
+  },
+  {
+    0x53, 0x02,
+    SenseDevTypes034,
+    "MEDIUM REMOVAL PREVENTED"
+  },
+  {
+    0x54, 0x00,
+    SenseDevTypes053,
+    "SCSI TO HOST SYSTEM INTERFACE FAILURE"
+  },
+  {
+    0x55, 0x00,
+    SenseDevTypes053,
+    "SYSTEM RESOURCE FAILURE"
+  },
+  {
+    0x55, 0x01,
+    SenseDevTypes033,
+    "SYSTEM BUFFER FULL"
+  },
+  {
+    0x55, 0x02,
+    SenseDevTypes054,
+    "INSUFFICIENT RESERVATION RESOURCES"
+  },
+  {
+    0x55, 0x03,
+    SenseDevTypes041,
+    "INSUFFICIENT RESOURCES"
+  },
+  {
+    0x55, 0x04,
+    SenseDevTypes055,
+    "INSUFFICIENT REGISTRATION RESOURCES"
+  },
+  {
+    0x55, 0x05,
+    SenseDevTypes012,
+    "access controls code 4 (99-314) [proposed]"
+  },
+  {
+    0x55, 0x06,
+    SenseDevTypes012,
+    "auxiliary memory code 1 (99-148) [proposed]"
+  },
+  {
+    0x57, 0x00,
+    SenseDevTypes005,
+    "UNABLE TO RECOVER TABLE-OF-CONTENTS"
+  },
+  {
+    0x58, 0x00,
+    SenseDevTypes056,
+    "GENERATION DOES NOT EXIST"
+  },
+  {
+    0x59, 0x00,
+    SenseDevTypes056,
+    "UPDATED BLOCK READ"
+  },
+  {
+    0x5A, 0x00,
+    SenseDevTypes057,
+    "OPERATOR REQUEST OR STATE CHANGE INPUT"
+  },
+  {
+    0x5A, 0x01,
+    SenseDevTypes034,
+    "OPERATOR MEDIUM REMOVAL REQUEST"
+  },
+  {
+    0x5A, 0x02,
+    SenseDevTypes058,
+    "OPERATOR SELECTED WRITE PROTECT"
+  },
+  {
+    0x5A, 0x03,
+    SenseDevTypes058,
+    "OPERATOR SELECTED WRITE PERMIT"
+  },
+  {
+    0x5B, 0x00,
+    SenseDevTypes059,
+    "LOG EXCEPTION"
+  },
+  {
+    0x5B, 0x01,
+    SenseDevTypes059,
+    "THRESHOLD CONDITION MET"
+  },
+  {
+    0x5B, 0x02,
+    SenseDevTypes059,
+    "LOG COUNTER AT MAXIMUM"
+  },
+  {
+    0x5B, 0x03,
+    SenseDevTypes059,
+    "LOG LIST CODES EXHAUSTED"
+  },
+  {
+    0x5C, 0x00,
+    SenseDevTypes060,
+    "RPL STATUS CHANGE"
+  },
+  {
+    0x5C, 0x01,
+    SenseDevTypes060,
+    "SPINDLES SYNCHRONIZED"
+  },
+  {
+    0x5C, 0x02,
+    SenseDevTypes060,
+    "SPINDLES NOT SYNCHRONIZED"
+  },
+  {
+    0x5D, 0x00,
+    SenseDevTypes001,
+    "FAILURE PREDICTION THRESHOLD EXCEEDED"
+  },
+  {
+    0x5D, 0x01,
+    SenseDevTypes061,
+    "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED"
+  },
+  {
+    0x5D, 0x02,
+    SenseDevTypes005,
+    "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED"
+  },
+  {
+    0x5D, 0x10,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x11,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x12,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x13,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x14,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x15,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x16,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x17,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x18,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x19,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x1A,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x1B,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x1C,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x20,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x21,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x22,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x23,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x24,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x25,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x26,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x27,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x28,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x29,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x2A,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x2B,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x2C,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x30,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x31,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x32,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x33,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x34,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x35,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x36,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x37,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x38,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x39,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x3A,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x3B,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x3C,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x40,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x41,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x42,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x43,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x44,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x45,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x46,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x47,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x48,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x49,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x4A,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x4B,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x4C,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x50,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x51,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x52,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x53,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x54,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x55,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x56,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x57,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x58,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x59,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x5A,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x5B,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x5C,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x60,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x61,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x62,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x63,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x64,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x65,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x66,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x67,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x68,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x69,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x6A,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x6B,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x6C,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0xFF,
+    SenseDevTypes001,
+    "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"
+  },
+  {
+    0x5E, 0x00,
+    SenseDevTypes044,
+    "LOW POWER CONDITION ON"
+  },
+  {
+    0x5E, 0x01,
+    SenseDevTypes044,
+    "IDLE CONDITION ACTIVATED BY TIMER"
+  },
+  {
+    0x5E, 0x02,
+    SenseDevTypes044,
+    "STANDBY CONDITION ACTIVATED BY TIMER"
+  },
+  {
+    0x5E, 0x03,
+    SenseDevTypes044,
+    "IDLE CONDITION ACTIVATED BY COMMAND"
+  },
+  {
+    0x5E, 0x04,
+    SenseDevTypes044,
+    "STANDBY CONDITION ACTIVATED BY COMMAND"
+  },
+  {
+    0x5E, 0x41,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO ACTIVE"
+  },
+  {
+    0x5E, 0x42,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO IDLE"
+  },
+  {
+    0x5E, 0x43,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO STANDBY"
+  },
+  {
+    0x5E, 0x45,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO SLEEP"
+  },
+  {
+    0x5E, 0x47,
+    SenseDevTypes063,
+    "POWER STATE CHANGE TO DEVICE CONTROL"
+  },
+  {
+    0x60, 0x00,
+    SenseDevTypes042,
+    "LAMP FAILURE"
+  },
+  {
+    0x61, 0x00,
+    SenseDevTypes042,
+    "VIDEO ACQUISITION ERROR"
+  },
+  {
+    0x61, 0x01,
+    SenseDevTypes042,
+    "UNABLE TO ACQUIRE VIDEO"
+  },
+  {
+    0x61, 0x02,
+    SenseDevTypes042,
+    "OUT OF FOCUS"
+  },
+  {
+    0x62, 0x00,
+    SenseDevTypes042,
+    "SCAN HEAD POSITIONING ERROR"
+  },
+  {
+    0x63, 0x00,
+    SenseDevTypes005,
+    "END OF USER AREA ENCOUNTERED ON THIS TRACK"
+  },
+  {
+    0x63, 0x01,
+    SenseDevTypes005,
+    "PACKET DOES NOT FIT IN AVAILABLE SPACE"
+  },
+  {
+    0x64, 0x00,
+    SenseDevTypes005,
+    "ILLEGAL MODE FOR THIS TRACK"
+  },
+  {
+    0x64, 0x01,
+    SenseDevTypes005,
+    "INVALID PACKET SIZE"
+  },
+  {
+    0x65, 0x00,
+    SenseDevTypes001,
+    "VOLTAGE FAULT"
+  },
+  {
+    0x66, 0x00,
+    SenseDevTypes042,
+    "AUTOMATIC DOCUMENT FEEDER COVER UP"
+  },
+  {
+    0x66, 0x01,
+    SenseDevTypes042,
+    "AUTOMATIC DOCUMENT FEEDER LIFT UP"
+  },
+  {
+    0x66, 0x02,
+    SenseDevTypes042,
+    "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"
+  },
+  {
+    0x66, 0x03,
+    SenseDevTypes042,
+    "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"
+  },
+  {
+    0x67, 0x00,
+    SenseDevTypes064,
+    "CONFIGURATION FAILURE"
+  },
+  {
+    0x67, 0x01,
+    SenseDevTypes064,
+    "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"
+  },
+  {
+    0x67, 0x02,
+    SenseDevTypes064,
+    "ADD LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x03,
+    SenseDevTypes064,
+    "MODIFICATION OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x04,
+    SenseDevTypes064,
+    "EXCHANGE OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x05,
+    SenseDevTypes064,
+    "REMOVE OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x06,
+    SenseDevTypes064,
+    "ATTACHMENT OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x07,
+    SenseDevTypes064,
+    "CREATION OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x08,
+    SenseDevTypes064,
+    "ASSIGN FAILURE OCCURRED"
+  },
+  {
+    0x67, 0x09,
+    SenseDevTypes064,
+    "MULTIPLY ASSIGNED LOGICAL UNIT"
+  },
+  {
+    0x68, 0x00,
+    SenseDevTypes064,
+    "LOGICAL UNIT NOT CONFIGURED"
+  },
+  {
+    0x69, 0x00,
+    SenseDevTypes064,
+    "DATA LOSS ON LOGICAL UNIT"
+  },
+  {
+    0x69, 0x01,
+    SenseDevTypes064,
+    "MULTIPLE LOGICAL UNIT FAILURES"
+  },
+  {
+    0x69, 0x02,
+    SenseDevTypes064,
+    "PARITY/DATA MISMATCH"
+  },
+  {
+    0x6A, 0x00,
+    SenseDevTypes064,
+    "INFORMATIONAL, REFER TO LOG"
+  },
+  {
+    0x6B, 0x00,
+    SenseDevTypes064,
+    "STATE CHANGE HAS OCCURRED"
+  },
+  {
+    0x6B, 0x01,
+    SenseDevTypes064,
+    "REDUNDANCY LEVEL GOT BETTER"
+  },
+  {
+    0x6B, 0x02,
+    SenseDevTypes064,
+    "REDUNDANCY LEVEL GOT WORSE"
+  },
+  {
+    0x6C, 0x00,
+    SenseDevTypes064,
+    "REBUILD FAILURE OCCURRED"
+  },
+  {
+    0x6D, 0x00,
+    SenseDevTypes064,
+    "RECALCULATE FAILURE OCCURRED"
+  },
+  {
+    0x6E, 0x00,
+    SenseDevTypes064,
+    "COMMAND TO LOGICAL UNIT FAILED"
+  },
+  {
+    0x6F, 0x00,
+    SenseDevTypes005,
+    "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"
+  },
+  {
+    0x6F, 0x01,
+    SenseDevTypes005,
+    "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"
+  },
+  {
+    0x6F, 0x02,
+    SenseDevTypes005,
+    "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"
+  },
+  {
+    0x6F, 0x03,
+    SenseDevTypes005,
+    "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"
+  },
+  {
+    0x6F, 0x04,
+    SenseDevTypes005,
+    "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"
+  },
+  {
+    0x6F, 0x05,
+    SenseDevTypes005,
+    "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"
+  },
+  {
+    0x70, 0xFF,
+    SenseDevTypes002,
+    "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN"
+  },
+  {
+    0x71, 0x00,
+    SenseDevTypes002,
+    "DECOMPRESSION EXCEPTION LONG ALGORITHM ID"
+  },
+  {
+    0x72, 0x00,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR"
+  },
+  {
+    0x72, 0x01,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR WRITING LEAD-IN"
+  },
+  {
+    0x72, 0x02,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR WRITING LEAD-OUT"
+  },
+  {
+    0x72, 0x03,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"
+  },
+  {
+    0x72, 0x04,
+    SenseDevTypes005,
+    "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"
+  },
+  {
+    0x72, 0x05,
+    SenseDevTypes005,
+    "NO MORE TRACK RESERVATIONS ALLOWED"
+  },
+  {
+    0x73, 0x00,
+    SenseDevTypes005,
+    "CD CONTROL ERROR"
+  },
+  {
+    0x73, 0x01,
+    SenseDevTypes005,
+    "POWER CALIBRATION AREA ALMOST FULL"
+  },
+  {
+    0x73, 0x02,
+    SenseDevTypes005,
+    "POWER CALIBRATION AREA IS FULL"
+  },
+  {
+    0x73, 0x03,
+    SenseDevTypes005,
+    "POWER CALIBRATION AREA ERROR"
+  },
+  {
+    0x73, 0x04,
+    SenseDevTypes005,
+    "PROGRAM MEMORY AREA UPDATE FAILURE"
+  },
+  {
+    0x73, 0x05,
+    SenseDevTypes005,
+    "PROGRAM MEMORY AREA IS FULL"
+  },
+  {
+    0x73, 0x06,
+    SenseDevTypes005,
+    "RMA/PMA IS FULL"
+  },
+};
+
+static int ASCQ_TableSize = 463;
+
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/ascq_tbl.sh linux/drivers/message/fusion/ascq_tbl.sh
--- v2.4.6/linux/drivers/message/fusion/ascq_tbl.sh	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/ascq_tbl.sh	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,109 @@
+#!/bin/sh
+#
+#  ascq_tbl.sh - Translate SCSI t10.org's "asc-num.txt" file of
+#                SCSI Additional Sense Code & Qualifiers (ASC/ASCQ's)
+#                into something useful in C, creating "ascq_tbl.c" file.
+#
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+PREF_INFILE="t10.org/asc-num.txt"	# From SCSI t10.org
+PREF_OUTFILE="ascq_tbl.c"
+
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+xlate_ascq() {
+	cat | awk '
+	BEGIN {
+		DQ = "\042";
+		OUTFILE = "'"${PREF_OUTFILE}"'";
+		TRUE = 1;
+		FALSE = 0;
+		#debug = TRUE;
+
+		#  read and discard all lines up to and including the one that begins
+		#  with the "magic token" of "-------  --------------  ---"...
+		headers_gone = FALSE;
+		while (!headers_gone) {
+			if (getline <= 0)
+				exit 1;
+			header_line[++hdrs] = $0;
+			if (debug)
+				printf("header_line[%d] = :%s:\n", ++hdrs, $0);
+			if ($0 ~ /^-------  --------------  ---/) {
+				headers_gone = TRUE;
+			}
+		}
+		outcount = 0;
+	}
+
+	(NF > 1) {
+		++outcount;
+		if (debug)
+			printf( "DBG: %s\n", $0 );
+		ASC[outcount] = substr($0,1,2);
+		ASCQ[outcount] = substr($0,5,2);
+		devtypes = substr($0,10,14);
+		gsub(/ /, ".", devtypes);
+		DESCRIP[outcount] = substr($0,26);
+
+		if (!(devtypes in DevTypesVoodoo)) {
+			DevTypesVoodoo[devtypes] = ++voodoo;
+			DevTypesIdx[voodoo] = devtypes;
+		}
+		DEVTYPES[outcount] = DevTypesVoodoo[devtypes];
+
+		#  Handle 0xNN exception stuff...
+		if (ASCQ[outcount] == "NN" || ASCQ[outcount] == "nn")
+			ASCQ[outcount] = "FF";
+	}
+
+	END {
+		printf("#ifndef SCSI_ASCQ_TBL_C_INCLUDED\n") > OUTFILE;
+		printf("#define SCSI_ASCQ_TBL_C_INCLUDED\n") >> OUTFILE;
+
+		printf("\n/* AuToMaGiCaLlY generated from: %s'"${FIN}"'%s\n", DQ, DQ) >> OUTFILE;
+		printf(" *******************************************************************************\n") >> OUTFILE;
+		for (i=1; i<=hdrs; i++) {
+			printf(" * %s\n", header_line[i]) >> OUTFILE;
+		}
+		printf(" */\n") >> OUTFILE;
+
+		printf("\n") >> OUTFILE;
+		for (i=1; i<=voodoo; i++) {
+			printf("static char SenseDevTypes%03d[] = %s%s%s;\n", i, DQ, DevTypesIdx[i], DQ) >> OUTFILE;
+		}
+
+		printf("\nstatic ASCQ_Table_t ASCQ_Table[] = {\n") >> OUTFILE;
+		for (i=1; i<=outcount; i++) {
+			printf("  {\n") >> OUTFILE; 
+			printf("    0x%s, 0x%s,\n", ASC[i], ASCQ[i]) >> OUTFILE;
+			printf("    SenseDevTypes%03d,\n", DEVTYPES[i]) >> OUTFILE;
+			printf("    %s%s%s\n", DQ, DESCRIP[i], DQ) >> OUTFILE;
+			printf("  },\n") >> OUTFILE;
+		}
+		printf( "};\n\n" ) >> OUTFILE;
+
+		printf( "static int ASCQ_TableSize = %d;\n\n", outcount ) >> OUTFILE;
+		printf( "Total of %d ASC/ASCQ records generated\n", outcount );
+		printf("\n#endif\n") >> OUTFILE;
+		close(OUTFILE);
+	}'
+	return
+}
+
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+# main()
+if [ $# -lt 1 ]; then
+	echo "INFO: No input filename supplied - using: $PREF_INFILE" >&2
+	FIN=$PREF_INFILE
+else
+	FIN="$1"
+	if [ "$FIN" != "$PREF_INFILE" ]; then
+		echo "INFO: Ok, I'll try chewing on '$FIN' for SCSI ASC/ASCQ combos..." >&2
+	fi
+	shift
+fi
+
+cat $FIN | xlate_ascq
+exit 0
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/isense.c linux/drivers/message/fusion/isense.c
--- v2.4.6/linux/drivers/message/fusion/isense.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/isense.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,122 @@
+/*
+ *  linux/drivers/message/fusion/isense.c
+ *      Little linux driver / shim that interfaces with the Fusion MPT
+ *      Linux base driver to provide english readable strings in SCSI
+ *      Error Report logging output.  This module implements SCSI-3
+ *      Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings.
+ *
+ *  Copyright (c) 1991-2001 Steven J. Ralston
+ *  Written By: Steven J. Ralston
+ *  (yes I wrote some of the orig. code back in 1991!)
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: isense.c,v 1.28 2001/01/14 23:11:09 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#include <asm/spinlock.h>
+#endif
+
+#define MODULEAUTHOR "Steven J. Ralston"
+#define COPYRIGHT "Copyright (c) 2000 " MODULEAUTHOR
+#include "mptbase.h"
+
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+
+/*
+ *  YIKES!  I don't usually #include C source files, but..
+ *  The following #include's pulls in our needed ASCQ_Table[] array,
+ *  ASCQ_TableSz integer, and ScsiOpcodeString[] array!
+ */
+#include "ascq_tbl.c"
+#include "scsiops.c"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME		"SCSI-3 Opcodes & ASC/ASCQ Strings"
+#define my_VERSION	MPT_LINUX_VERSION_COMMON
+#define MYNAM		"isense"
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init isense_init(void)
+{
+	show_mptmod_ver(my_NAME, my_VERSION);
+
+	/*
+	 *  Install our handler
+	 */
+	if (mpt_register_ascqops_strings(&ASCQ_Table[0], ASCQ_TableSize, ScsiOpcodeString) != 1)
+	{
+		printk(KERN_ERR MYNAM ": ERROR: Can't register with Fusion MPT base driver!\n");
+		return -EBUSY;
+	}
+	printk(KERN_INFO MYNAM ": Registered SCSI-3 Opcodes & ASC/ASCQ Strings\n");
+	return 0;
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void isense_exit(void)
+{
+#ifdef MODULE
+	mpt_deregister_ascqops_strings();
+#endif
+	printk(KERN_INFO MYNAM ": Deregistered SCSI-3 Opcodes & ASC/ASCQ Strings\n");
+}
+
+module_init(isense_init);
+module_exit(isense_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/isense.h linux/drivers/message/fusion/isense.h
--- v2.4.6/linux/drivers/message/fusion/isense.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/isense.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,95 @@
+#ifndef ISENSE_H_INCLUDED
+#define ISENSE_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifdef __KERNEL__
+#include <linux/types.h>		/* needed for u8, etc. */
+#include <linux/string.h>		/* needed for strcat   */
+#include <linux/kernel.h>		/* needed for sprintf  */
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+#include "scsi3.h"			/* needed for all things SCSI */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Defines and typedefs...
+ */
+
+#ifdef __KERNEL__
+#define PrintF(x) printk x
+#else
+#define PrintF(x) printf x
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define RETRY_STATUS  ((int) 1)
+#define PUT_STATUS    ((int) 0)
+
+/*
+ *    A generic structure to hold info about IO request that caused
+ *    a Request Sense to be performed, and the resulting Sense Data.
+ */
+typedef struct IO_Info
+{
+    char *DevIDStr;   /* String of chars which identifies the device.       */
+    u8   *cdbPtr;     /* Pointer (Virtual/Logical addr) to CDB bytes of
+                           IO request that caused ContAllegianceCond.       */
+    u8   *sensePtr;   /* Pointer (Virtual/Logical addr) to Sense Data
+                           returned by Request Sense operation.             */
+    u8   *dataPtr;    /* Pointer (Virtual/Logical addr) to Data buffer
+                           of IO request caused ContAllegianceCondition.    */
+    u8   *inqPtr;     /* Pointer (Virtual/Logical addr) to Inquiry Data for
+                           IO *Device* that caused ContAllegianceCondition. */
+    u8    SCSIStatus; /* SCSI status byte of IO request that caused
+                           Contingent Allegiance Condition.                 */
+    u8    DoDisplay;  /* Shall we display any messages?                     */
+    u16   rsvd_align1;
+    u32   ComplCode;  /* Four-byte OS-dependent completion code.            */
+    u32   NotifyL;    /* Four-byte OS-dependent notification field.         */
+} IO_Info_t;
+
+/*
+ *  SCSI Additional Sense Code and Additional Sense Code Qualifier table.
+ */
+typedef struct ASCQ_Table
+{
+    u8     ASC;
+    u8     ASCQ;
+    char  *DevTypes;
+    char  *Description;
+} ASCQ_Table_t;
+
+#if 0
+/*
+ *  SCSI Opcodes table.
+ */
+typedef struct SCSI_OPS_Table
+{
+    u8     OpCode;
+    char  *DevTypes;
+    char  *ScsiCmndStr;
+} SCSI_OPS_Table_t;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public entry point prototypes
+ */
+
+/* in scsiherr.c, needed by mptscsih.c */
+extern int	 mpt_ScsiHost_ErrorReport(IO_Info_t *ioop);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/linux_compat.h linux/drivers/message/fusion/linux_compat.h
--- v2.4.6/linux/drivers/message/fusion/linux_compat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/linux_compat.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,199 @@
+/* drivers/message/fusion/linux_compat.h */
+
+#ifndef FUSION_LINUX_COMPAT_H
+#define FUSION_LINUX_COMPAT_H
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#	if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+		typedef unsigned int dma_addr_t;
+#	endif
+#else
+#	if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42)
+		typedef unsigned int dma_addr_t;
+#	endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* This block snipped from lk-2.2.18/include/linux/init.h { */
+/*
+ * 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
+/* 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)	__initcall(x);
+#define module_exit(x)	__exitcall(x);
+#endif
+/* } block snipped from lk-2.2.18/include/linux/init.h */
+
+/* Wait queues. */
+#define DECLARE_WAIT_QUEUE_HEAD(name)	\
+	struct wait_queue * (name) = NULL
+#define DECLARE_WAITQUEUE(name, task)	\
+	struct wait_queue (name) = { (task), NULL }
+
+#if defined(__sparc__) && defined(__sparc_v9__)
+/* The sparc64 ioremap implementation is wrong in 2.2.x,
+ * but fixing it would break all of the drivers which
+ * workaround it.  Fixed in 2.3.x onward. -DaveM
+ */
+#define ARCH_IOREMAP(base)	((unsigned long) (base))
+#else
+#define ARCH_IOREMAP(base)	ioremap(base)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#else		/* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */
+
+/* No ioremap bugs in >2.3.x kernels. */
+#define ARCH_IOREMAP(base)	ioremap(base)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif		/* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
+
+
+/* PCI/driver subsystem { */
+#ifndef pci_for_each_dev
+#define pci_for_each_dev(dev)		for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next)
+#define pci_peek_next_dev(dev)		((dev)->next ? (dev)->next : NULL)
+#define DEVICE_COUNT_RESOURCE           6
+#define PCI_BASEADDR_FLAGS(idx)         base_address[idx]
+#define PCI_BASEADDR_START(idx)         base_address[idx] & ~0xFUL
+/*
+ * We have to keep track of the original value using
+ * a temporary, and not by just sticking pdev->base_address[x]
+ * back.  pdev->base_address[x] is an opaque cookie that can
+ * be used by the PCI implementation on a given Linux port
+ * for any purpose. -DaveM
+ */
+#define PCI_BASEADDR_SIZE(__pdev, __idx) \
+({	unsigned int size, tmp; \
+	pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \
+	pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \
+	pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \
+	pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \
+	(4 - size); \
+})
+#else
+#define pci_peek_next_dev(dev)		((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL)
+#define PCI_BASEADDR_FLAGS(idx)         resource[idx].flags
+#define PCI_BASEADDR_START(idx)         resource[idx].start
+#define PCI_BASEADDR_SIZE(dev,idx)      (dev)->resource[idx].end - (dev)->resource[idx].start + 1
+#endif		/* } ifndef pci_for_each_dev */
+
+
+/* procfs compat stuff... */
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+#define CREATE_PROCDIR_ENTRY(x,y)  create_proc_entry(x, S_IFDIR, y)
+/* This is a macro so we don't need to pull all the procfs
+ * headers into this file. -DaveM
+ */
+#define create_proc_read_entry(name, mode, base, __read_proc, __data) \
+({      struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \
+        if (__res) { \
+                __res->read_proc=(__read_proc); \
+                __res->data=(__data); \
+        } \
+        __res; \
+})
+#else
+#define CREATE_PROCDIR_ENTRY(x,y)  proc_mkdir(x, y)
+#endif
+#endif
+
+/* Compatability for the 2.3.x PCI DMA API. */
+#ifndef PCI_DMA_BIDIRECTIONAL
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define PCI_DMA_BIDIRECTIONAL	0
+#define PCI_DMA_TODEVICE	1
+#define PCI_DMA_FROMDEVICE	2
+#define PCI_DMA_NONE		3
+
+#ifdef __KERNEL__
+#include <asm/page.h>
+/* Pure 2^n version of get_order */
+static __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
+
+#define pci_alloc_consistent(hwdev, size, dma_handle) \
+({	void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \
+	if (__ret != NULL) { \
+		memset(__ret, 0, size); \
+		*(dma_handle) = virt_to_bus(__ret); \
+	} \
+	__ret; \
+})
+
+#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \
+	free_pages((unsigned long)vaddr, __get_order(size))
+
+#define pci_map_single(hwdev, ptr, size, direction) \
+	virt_to_bus(ptr);
+
+#define pci_unmap_single(hwdev, dma_addr, size, direction) \
+	do { /* Nothing to do */ } while (0)
+
+#define pci_map_sg(hwdev, sg, nents, direction)	(nents)
+#define pci_unmap_sg(hwdev, sg, nents, direction) \
+	do { /* Nothing to do */ } while(0)
+
+#define sg_dma_address(sg)	(virt_to_bus((sg)->address))
+#define sg_dma_len(sg)		((sg)->length)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* PCI_DMA_BIDIRECTIONAL */
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* _LINUX_COMPAT_H */
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/fc_log.h linux/drivers/message/fusion/lsi/fc_log.h
--- v2.4.6/linux/drivers/message/fusion/lsi/fc_log.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/fc_log.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *
+ *  NAME:           fc_log.h
+ *  SUMMARY:        MPI IocLogInfo definitions for the SYMFC9xx chips
+ *  DESCRIPTION:    Contains the enumerated list of values that may be returned
+ *                  in the IOCLogInfo field of a MPI Default Reply Message.
+ *
+ *  CREATION DATE:  6/02/2000
+ *  ID:             $Id: fc_log.h,v 4.2 2001/03/01 18:28:59 fibre Exp $
+ */
+
+
+/*
+ * MpiIocLogInfo_t enum
+ *
+ * These 32 bit values are used in the IOCLogInfo field of the MPI reply
+ * messages.
+ * The value is 0xabcccccc where
+ *          a = The type of log info as per the MPI spec. Since these codes are
+ *              all for Fibre Channel this value will always be 2.
+ *          b = Specifies a subclass of the firmware where
+ *                  0 = FCP Initiator
+ *                  1 = FCP Target
+ *                  2 = LAN
+ *                  3 = MPI Message Layer
+ *                  4 = FC Link
+ *                  5 = Context Manager
+ *                  6 = Invalid Field Offset
+ *                  7 = State Change Info
+ *                  all others are reserved for future use
+ *          c = A specific value within the subclass.
+ *
+ * NOTE: Any new values should be added to the end of each subclass so that the
+ *       codes remain consistent across firmware releases.
+ */
+typedef enum _MpiIocLogInfoFc
+{
+    MPI_IOCLOGINFO_FC_INIT_BASE                     = 0x20000000,
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* bad start of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME   = 0x20000003, /* bad end of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN           = 0x20000004, /* Receiver hardware detected overrun */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER           = 0x20000005, /* Other errors caught by IOC which require retries */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD       = 0x20000006, /* Main processor could not initialize sub-processor */
+
+    MPI_IOCLOGINFO_FC_TARGET_BASE                   = 0x21000000,
+    MPI_IOCLOGINFO_FC_TARGET_NO_PDISC               = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
+    MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN               = 0x21000002, /* not sent because we are not logged in to the remote node */
+    MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP     = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP     = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA      = 0x21000005, /* Data In, Auto Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP     = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP     = 0x21000007, /* Auto-response after a write not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP     = 0x21000008, /* Data In, No Response, not completed due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA      = 0x21000009, /* Data In, No Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP     = 0x2100000a, /* Manual Response not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3             = 0x2100000b, /* not sent because remote node does not support Class 3 */
+    MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID        = 0x2100000c, /* not sent because login to remote node not validated */
+    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound after a logout */
+    MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN    = 0x2100000f, /* cleared waiting for data after a logout */
+
+    MPI_IOCLOGINFO_FC_LAN_BASE                      = 0x22000000,
+    MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING         = 0x22000001, /* Transaction Context Sgl Missing */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE         = 0x22000002, /* Transaction Context found before an EOB */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET        = 0x22000003, /* Transaction Context value has reserved bits set */
+    MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG            = 0x22000004, /* Invalid SGL Flags */
+
+    MPI_IOCLOGINFO_FC_MSG_BASE                      = 0x23000000,
+
+    MPI_IOCLOGINFO_FC_LINK_BASE                     = 0x24000000,
+    MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT        = 0x24000001, /* Loop initialization timed out */
+    MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED      = 0x24000002, /* Another system controller already initialized the loop */
+    MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED     = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
+
+    MPI_IOCLOGINFO_FC_CTX_BASE                      = 0x25000000,
+
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET     = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid. */
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET      = 0x26ffffff,
+
+    MPI_IOCLOGINFO_FC_STATE_CHANGE                  = 0x27000000  /* The lower 24 bits give additional information concerning state change */
+
+} MpiIocLogInfoFc_t;
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi.h linux/drivers/message/fusion/lsi/mpi.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,643 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI.H
+ *          Title:  MPI Message independent structures and definitions
+ *  Creation Date:  July 27, 2000
+ *
+ *    MPI Version:  01.01.06
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ *  06-06-00  01.00.01  Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ *  06-22-00  01.00.02  Added MPI_IOCSTATUS_LAN_ definitions.
+ *                      Removed LAN_SUSPEND function definition.
+ *                      Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ *  06-30-00  01.00.03  Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ *                      Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ *  07-27-00  01.00.04  Added MPI_FAULT_ definitions.
+ *                      Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ *                      Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ *                      Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *  12-04-00  01.01.02  Added new function codes.
+ *  01-09-01  01.01.03  Added more definitions to the system interface section
+ *                      Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ *  01-25-01  01.01.04  Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *                      Fixed value for MPI_DIAG_RW_ENABLE.
+ *                      Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ *                      MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ *                      Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ *  02-27-01  01.01.06  Removed MPI_HOST_INDEX_REGISTER define.
+ *                      Added function codes for RAID.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_H
+#define MPI_H
+
+
+/*****************************************************************************
+*
+*        M P I    V e r s i o n    D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_VERSION_MAJOR                   (0x01)
+#define MPI_VERSION_MINOR                   (0x01)
+#define MPI_VERSION            ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
+
+/* Note: The major versions of 0xe0 through 0xff are reserved */
+
+/*****************************************************************************
+*
+*        I O C    S t a t e    D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_IOC_STATE_RESET                 (0x00000000)
+#define MPI_IOC_STATE_READY                 (0x10000000)
+#define MPI_IOC_STATE_OPERATIONAL           (0x20000000)
+#define MPI_IOC_STATE_FAULT                 (0x40000000)
+
+#define MPI_IOC_STATE_MASK                  (0xF0000000)
+#define MPI_IOC_STATE_SHIFT                 (28)
+
+/* Fault state codes (product independent range 0x8000-0xFFFF) */
+
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_PARITY_ERROR  (0x8111)
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_BUS_FAULT     (0x8112)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_PARITY_ERROR    (0x8113)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_BUS_FAULT       (0x8114)
+#define MPI_FAULT_DATA_SEND_PCI_PARITY_ERROR        (0x8115)
+#define MPI_FAULT_DATA_SEND_PCI_BUS_FAULT           (0x8116)
+#define MPI_FAULT_DATA_RECEIVE_PCI_PARITY_ERROR     (0x8117)
+#define MPI_FAULT_DATA_RECEIVE_PCI_BUS_FAULT        (0x8118)
+
+
+/*****************************************************************************
+*
+*        P C I    S y s t e m    I n t e r f a c e    R e g i s t e r s
+*
+*****************************************************************************/
+
+/* S y s t e m    D o o r b e l l */
+#define MPI_DOORBELL_OFFSET                 (0x00000000)
+#define MPI_DOORBELL_ACTIVE                 (0x08000000)
+#define MPI_DOORBELL_ACTIVE_SHIFT           (27)
+#define MPI_DOORBELL_WHO_INIT_MASK          (0x07000000)
+#define MPI_DOORBELL_WHO_INIT_SHIFT         (24)
+#define MPI_DOORBELL_FUNCTION_MASK          (0xFF000000)
+#define MPI_DOORBELL_FUNCTION_SHIFT         (24)
+#define MPI_DOORBELL_ADD_DWORDS_MASK        (0x00FF0000)
+#define MPI_DOORBELL_ADD_DWORDS_SHIFT       (16)
+#define MPI_DOORBELL_DATA_MASK              (0x0000FFFF)
+
+
+#define MPI_WRITE_SEQUENCE_OFFSET           (0x00000004)
+#define MPI_WRSEQ_KEY_VALUE_MASK            (0x0000000F)
+#define MPI_WRSEQ_1ST_KEY_VALUE             (0x04)
+#define MPI_WRSEQ_2ND_KEY_VALUE             (0x0B)
+#define MPI_WRSEQ_3RD_KEY_VALUE             (0x02)
+#define MPI_WRSEQ_4TH_KEY_VALUE             (0x07)
+#define MPI_WRSEQ_5TH_KEY_VALUE             (0x0D)
+
+#define MPI_DIAGNOSTIC_OFFSET               (0x00000008)
+#define MPI_DIAG_CLEAR_FLASH_BAD_SIG        (0x00000400)
+#define MPI_DIAG_PREVENT_IOC_BOOT           (0x00000200)
+#define MPI_DIAG_DRWE                       (0x00000080)
+#define MPI_DIAG_FLASH_BAD_SIG              (0x00000040)
+#define MPI_DIAG_RESET_HISTORY              (0x00000020)
+#define MPI_DIAG_RW_ENABLE                  (0x00000010)
+#define MPI_DIAG_RESET_ADAPTER              (0x00000004)
+#define MPI_DIAG_DISABLE_ARM                (0x00000002)
+#define MPI_DIAG_MEM_ENABLE                 (0x00000001)
+
+#define MPI_TEST_BASE_ADDRESS_OFFSET        (0x0000000C)
+
+#define MPI_DIAG_RW_DATA_OFFSET             (0x00000010)
+
+#define MPI_DIAG_RW_ADDRESS_OFFSET          (0x00000014)
+
+#define MPI_HOST_INTERRUPT_STATUS_OFFSET    (0x00000030)
+#define MPI_HIS_IOP_DOORBELL_STATUS         (0x80000000)
+#define MPI_HIS_REPLY_MESSAGE_INTERRUPT     (0x00000008)
+#define MPI_HIS_DOORBELL_INTERRUPT          (0x00000001)
+
+#define MPI_HOST_INTERRUPT_MASK_OFFSET      (0x00000034)
+#define MPI_HIM_RIM                         (0x00000008)
+#define MPI_HIM_DIM                         (0x00000001)
+
+#define MPI_REQUEST_QUEUE_OFFSET            (0x00000040)
+#define MPI_REQUEST_POST_FIFO_OFFSET        (0x00000040)
+
+#define MPI_REPLY_QUEUE_OFFSET              (0x00000044)
+#define MPI_REPLY_POST_FIFO_OFFSET          (0x00000044)
+#define MPI_REPLY_FREE_FIFO_OFFSET          (0x00000044)
+
+
+
+/*****************************************************************************
+*
+*        M e s s a g e    F r a m e    D e s c r i p t o r s
+*
+*****************************************************************************/
+
+#define MPI_REQ_MF_DESCRIPTOR_NB_MASK       (0x00000003)
+#define MPI_REQ_MF_DESCRIPTOR_F_BIT         (0x00000004)
+#define MPI_REQ_MF_DESCRIPTOR_ADDRESS_MASK  (0xFFFFFFF8)
+
+#define MPI_ADDRESS_REPLY_A_BIT             (0x80000000)
+#define MPI_ADDRESS_REPLY_ADDRESS_MASK      (0x7FFFFFFF)
+
+#define MPI_CONTEXT_REPLY_A_BIT             (0x80000000)
+#define MPI_CONTEXT_REPLY_TYPE_MASK         (0x60000000)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_INIT    (0x00)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET  (0x01)
+#define MPI_CONTEXT_REPLY_TYPE_LAN          (0x02)
+#define MPI_CONTEXT_REPLY_TYPE_SHIFT        (29)
+#define MPI_CONTEXT_REPLY_CONTEXT_MASK      (0x1FFFFFFF)
+
+
+/****************************************************************************/
+/* Context Reply macros                                                     */
+/****************************************************************************/
+
+#define MPI_GET_CONTEXT_REPLY_TYPE(x)  (((x) & MPI_CONTEXT_REPLY_TYPE_MASK) \
+                                          >> MPI_CONTEXT_REPLY_TYPE_SHIFT)
+
+#define MPI_SET_CONTEXT_REPLY_TYPE(x, typ)                                  \
+            ((x) = ((x) & ~MPI_CONTEXT_REPLY_TYPE_MASK) |                   \
+                            (((typ) << MPI_CONTEXT_REPLY_TYPE_SHIFT) &      \
+                                        MPI_CONTEXT_REPLY_TYPE_MASK))
+
+
+/*****************************************************************************
+*
+*        M e s s a g e    F u n c t i o n s
+*              0x80 -> 0x8F reserved for private message use per product
+*
+*
+*****************************************************************************/
+
+#define MPI_FUNCTION_SCSI_IO_REQUEST                (0x00)
+#define MPI_FUNCTION_SCSI_TASK_MGMT                 (0x01)
+#define MPI_FUNCTION_IOC_INIT                       (0x02)
+#define MPI_FUNCTION_IOC_FACTS                      (0x03)
+#define MPI_FUNCTION_CONFIG                         (0x04)
+#define MPI_FUNCTION_PORT_FACTS                     (0x05)
+#define MPI_FUNCTION_PORT_ENABLE                    (0x06)
+#define MPI_FUNCTION_EVENT_NOTIFICATION             (0x07)
+#define MPI_FUNCTION_EVENT_ACK                      (0x08)
+#define MPI_FUNCTION_FW_DOWNLOAD                    (0x09)
+#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST         (0x0A)
+#define MPI_FUNCTION_TARGET_ASSIST                  (0x0B)
+#define MPI_FUNCTION_TARGET_STATUS_SEND             (0x0C)
+#define MPI_FUNCTION_TARGET_MODE_ABORT              (0x0D)
+#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC   (0x0E) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC        (0x0F) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC    (0x10) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_ABORT                (0x11) /* obsolete name */
+#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST          (0x0E)
+#define MPI_FUNCTION_FC_LINK_SRVC_RSP               (0x0F)
+#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND           (0x10)
+#define MPI_FUNCTION_FC_ABORT                       (0x11)
+#define MPI_FUNCTION_FW_UPLOAD                      (0x12)
+#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND       (0x13)
+#define MPI_FUNCTION_FC_PRIMITIVE_SEND              (0x14)
+
+#define MPI_FUNCTION_RAID_VOLUME                    (0x15)
+#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH       (0x16)
+
+#define MPI_FUNCTION_LAN_SEND                       (0x20)
+#define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
+#define MPI_FUNCTION_LAN_RESET                      (0x22)
+
+#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET         (0x40)
+#define MPI_FUNCTION_IO_UNIT_RESET                  (0x41)
+#define MPI_FUNCTION_HANDSHAKE                      (0x42)
+#define MPI_FUNCTION_REPLY_FRAME_REMOVAL            (0x43)
+
+
+
+/*****************************************************************************
+*
+*        S c a t t e r    G a t h e r    E l e m e n t s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Simple element structures                                               */
+/****************************************************************************/
+
+typedef struct _SGE_SIMPLE32
+{
+    U32                     FlagsLength;
+    U32                     Address;
+} SGE_SIMPLE32, MPI_POINTER PTR_SGE_SIMPLE32,
+  SGESimple32_t, MPI_POINTER pSGESimple32_t;
+
+typedef struct _SGE_SIMPLE64
+{
+    U32                     FlagsLength;
+    U64                     Address;
+} SGE_SIMPLE64, MPI_POINTER PTR_SGE_SIMPLE64,
+  SGESimple64_t, MPI_POINTER pSGESimple64_t;
+
+typedef struct _SGE_SIMPLE_UNION
+{
+    U32                     FlagsLength;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    }u;
+} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t,
+  SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION;
+
+/****************************************************************************/
+/*  Chain element structures                                                */
+/****************************************************************************/
+
+typedef struct _SGE_CHAIN32
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U32                     Address;
+} SGE_CHAIN32, MPI_POINTER PTR_SGE_CHAIN32,
+  SGEChain32_t, MPI_POINTER pSGEChain32_t;
+
+typedef struct _SGE_CHAIN64
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U64                     Address;
+} SGE_CHAIN64, MPI_POINTER PTR_SGE_CHAIN64,
+  SGEChain64_t, MPI_POINTER pSGEChain64_t;
+
+typedef struct _SGE_CHAIN_UNION
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    }u;
+} SGE_CHAIN_UNION, MPI_POINTER PTR_SGE_CHAIN_UNION,
+  SGEChainUnion_t, MPI_POINTER pSGEChainUnion_t;
+
+/****************************************************************************/
+/*  Transaction Context element                                             */
+/****************************************************************************/
+
+typedef struct _SGE_TRANSACTION32
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[1];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION32, MPI_POINTER PTR_SGE_TRANSACTION32,
+  SGETransaction32_t, MPI_POINTER pSGETransaction32_t;
+
+typedef struct _SGE_TRANSACTION64
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[2];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION64, MPI_POINTER PTR_SGE_TRANSACTION64,
+  SGETransaction64_t, MPI_POINTER pSGETransaction64_t;
+
+typedef struct _SGE_TRANSACTION96
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[3];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION96, MPI_POINTER PTR_SGE_TRANSACTION96,
+  SGETransaction96_t, MPI_POINTER pSGETransaction96_t;
+
+typedef struct _SGE_TRANSACTION128
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[4];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION128, MPI_POINTER PTR_SGE_TRANSACTION128,
+  SGETransaction_t128, MPI_POINTER pSGETransaction_t128;
+
+typedef struct _SGE_TRANSACTION_UNION
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    union
+    {
+        U32                 TransactionContext32[1];
+        U32                 TransactionContext64[2];
+        U32                 TransactionContext96[3];
+        U32                 TransactionContext128[4];
+    }u;
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION_UNION, MPI_POINTER PTR_SGE_TRANSACTION_UNION,
+  SGETransactionUnion_t, MPI_POINTER pSGETransactionUnion_t;
+
+
+/****************************************************************************/
+/*  SGE IO types union  for IO SGL's                                        */
+/****************************************************************************/
+
+typedef struct _SGE_IO_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION    Simple;
+        SGE_CHAIN_UNION     Chain;
+    } u;
+} SGE_IO_UNION, MPI_POINTER PTR_SGE_IO_UNION,
+  SGEIOUnion_t, MPI_POINTER pSGEIOUnion_t;
+
+/****************************************************************************/
+/*  SGE union for SGL's with Simple and Transaction elements                */
+/****************************************************************************/
+
+typedef struct _SGE_TRANS_SIMPLE_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION        Simple;
+        SGE_TRANSACTION_UNION   Transaction;
+    } u;
+} SGE_TRANS_SIMPLE_UNION, MPI_POINTER PTR_SGE_TRANS_SIMPLE_UNION,
+  SGETransSimpleUnion_t, MPI_POINTER pSGETransSimpleUnion_t;
+
+/****************************************************************************/
+/*  All SGE types union                                                     */
+/****************************************************************************/
+
+typedef struct _SGE_MPI_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION        Simple;
+        SGE_CHAIN_UNION         Chain;
+        SGE_TRANSACTION_UNION   Transaction;
+    } u;
+} SGE_MPI_UNION, MPI_POINTER PTR_SGE_MPI_UNION,
+  MPI_SGE_UNION_t, MPI_POINTER pMPI_SGE_UNION_t,
+  SGEAllUnion_t, MPI_POINTER pSGEAllUnion_t;
+
+
+/****************************************************************************/
+/*  SGE field definition and masks                                          */
+/****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI_SGE_FLAGS_LAST_ELEMENT              (0x80)
+#define MPI_SGE_FLAGS_END_OF_BUFFER             (0x40)
+#define MPI_SGE_FLAGS_ELEMENT_TYPE_MASK         (0x30)
+#define MPI_SGE_FLAGS_LOCAL_ADDRESS             (0x08)
+#define MPI_SGE_FLAGS_DIRECTION                 (0x04)
+#define MPI_SGE_FLAGS_ADDRESS_SIZE              (0x02)
+#define MPI_SGE_FLAGS_END_OF_LIST               (0x01)
+
+#define MPI_SGE_FLAGS_SHIFT                     (24)
+
+#define MPI_SGE_LENGTH_MASK                     (0x00FFFFFF)
+#define MPI_SGE_CHAIN_LENGTH_MASK               (0x0000FFFF)
+
+/* Element Type */
+
+#define MPI_SGE_FLAGS_TRANSACTION_ELEMENT       (0x00)
+#define MPI_SGE_FLAGS_SIMPLE_ELEMENT            (0x10)
+#define MPI_SGE_FLAGS_CHAIN_ELEMENT             (0x30)
+#define MPI_SGE_FLAGS_ELEMENT_MASK              (0x30)
+
+/* Address location */
+
+#define MPI_SGE_FLAGS_SYSTEM_ADDRESS            (0x00)
+
+/* Direction */
+
+#define MPI_SGE_FLAGS_IOC_TO_HOST               (0x00)
+#define MPI_SGE_FLAGS_HOST_TO_IOC               (0x04)
+
+/* Address Size */
+
+#define MPI_SGE_FLAGS_32_BIT_ADDRESSING         (0x00)
+#define MPI_SGE_FLAGS_64_BIT_ADDRESSING         (0x02)
+
+/* Context Size */
+
+#define MPI_SGE_FLAGS_32_BIT_CONTEXT            (0x00)
+#define MPI_SGE_FLAGS_64_BIT_CONTEXT            (0x02)
+#define MPI_SGE_FLAGS_96_BIT_CONTEXT            (0x04)
+#define MPI_SGE_FLAGS_128_BIT_CONTEXT           (0x06)
+
+#define MPI_SGE_CHAIN_OFFSET_MASK               (0x00FF0000)
+#define MPI_SGE_CHAIN_OFFSET_SHIFT              (16)
+
+
+/****************************************************************************/
+/*  SGE operation Macros                                                    */
+/****************************************************************************/
+
+         /* SIMPLE FlagsLength manipulations... */
+#define  MPI_SGE_SET_FLAGS(f)           ((U32)(f) << MPI_SGE_FLAGS_SHIFT)
+#define  MPI_SGE_GET_FLAGS(fl)          (((fl) & ~MPI_SGE_LENGTH_MASK) >> MPI_SGE_FLAGS_SHIFT)
+#define  MPI_SGE_LENGTH(fl)             ((fl) & MPI_SGE_LENGTH_MASK)
+#define  MPI_SGE_CHAIN_LENGTH(fl)       ((fl) & MPI_SGE_CHAIN_LENGTH_MASK)
+
+#define  MPI_SGE_SET_FLAGS_LENGTH(f,l)  (MPI_SGE_SET_FLAGS(f) | MPI_SGE_LENGTH(l))
+
+#define  MPI_pSGE_GET_FLAGS(psg)        MPI_SGE_GET_FLAGS((psg)->FlagsLength)
+#define  MPI_pSGE_GET_LENGTH(psg)       MPI_SGE_LENGTH((psg)->FlagsLength)
+#define  MPI_pSGE_SET_FLAGS_LENGTH(psg,f,l)  (psg)->FlagsLength = MPI_SGE_SET_FLAGS_LENGTH(f,l)
+         /* CAUTION - The following are READ-MODIFY-WRITE! */
+#define  MPI_pSGE_SET_FLAGS(psg,f)      (psg)->FlagsLength |= MPI_SGE_SET_FLAGS(f)
+#define  MPI_pSGE_SET_LENGTH(psg,l)     (psg)->FlagsLength |= MPI_SGE_LENGTH(l)
+
+#define  MPI_GET_CHAIN_OFFSET(x) ((x&MPI_SGE_CHAIN_OFFSET_MASK)>>MPI_SGE_CHAIN_OFFSET_SHIFT)
+
+
+
+/*****************************************************************************
+*
+*        S t a n d a r d    M e s s a g e    S t r u c t u r e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Standard message request header for all request messages                 */
+/****************************************************************************/
+
+typedef struct _MSG_REQUEST_HEADER
+{
+    U8                      Reserved[2];      /* function specific */
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];     /* function specific */
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_REQUEST_HEADER, MPI_POINTER PTR_MSG_REQUEST_HEADER,
+  MPIHeader_t, MPI_POINTER pMPIHeader_t;
+
+
+/****************************************************************************/
+/*  Default Reply                                                           */
+/****************************************************************************/
+
+typedef struct _MSG_DEFAULT_REPLY
+{
+    U8                      Reserved[2];      /* function specific */
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];     /* function specific */
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];     /* function specific */
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_DEFAULT_REPLY, MPI_POINTER PTR_MSG_DEFAULT_REPLY,
+  MPIDefaultReply_t, MPI_POINTER pMPIDefaultReply_t;
+
+
+/* MsgFlags definition for all replies */
+
+#define MPI_MSGFLAGS_CONTINUATION_REPLY         (0x80)
+
+
+/*****************************************************************************
+*
+*               I O C    S t a t u s   V a l u e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Common IOCStatus values for all replies                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SUCCESS                  (0x0000)
+#define MPI_IOCSTATUS_INVALID_FUNCTION         (0x0001)
+#define MPI_IOCSTATUS_BUSY                     (0x0002)
+#define MPI_IOCSTATUS_INVALID_SGL              (0x0003)
+#define MPI_IOCSTATUS_INTERNAL_ERROR           (0x0004)
+#define MPI_IOCSTATUS_RESERVED                 (0x0005)
+#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES   (0x0006)
+#define MPI_IOCSTATUS_INVALID_FIELD            (0x0007)
+#define MPI_IOCSTATUS_INVALID_STATE            (0x0008)
+
+/****************************************************************************/
+/*  Config IOCStatus values                                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION    (0x0020)
+#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE      (0x0021)
+#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE      (0x0022)
+#define MPI_IOCSTATUS_CONFIG_INVALID_DATA      (0x0023)
+#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS       (0x0024)
+#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT       (0x0025)
+
+/****************************************************************************/
+/*  SCSIIO Reply (SPI & FCP) initiator values                               */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR     (0x0040)
+#define MPI_IOCSTATUS_SCSI_INVALID_BUS         (0x0041)
+#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID    (0x0042)
+#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE    (0x0043)
+#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN        (0x0044)
+#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN       (0x0045)
+#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR       (0x0046)
+#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR      (0x0047)
+#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED     (0x0048)
+#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH   (0x0049)
+#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED    (0x004A)
+#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED      (0x004B)
+#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED      (0x004C)
+
+/****************************************************************************/
+/*  SCSI (SPI & FCP) target values                                          */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_PRIORITY_IO         (0x0060)
+#define MPI_IOCSTATUS_TARGET_INVALID_PORT        (0x0061)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)
+#define MPI_IOCSTATUS_TARGET_ABORTED             (0x0063)
+#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE   (0x0064)
+#define MPI_IOCSTATUS_TARGET_NO_CONNECTION       (0x0065)
+#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
+#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT   (0x006B)
+
+/****************************************************************************/
+/*  Additional FCP target values                                            */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_FC_ABORTED         (0x0066)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID   (0x0067)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID     (0x0068)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069)    /* obsolete */
+
+/****************************************************************************/
+/*  Fibre Channel Direct Access values                                      */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FC_ABORTED                (0x0066)
+#define MPI_IOCSTATUS_FC_RX_ID_INVALID          (0x0067)
+#define MPI_IOCSTATUS_FC_DID_INVALID            (0x0068)
+#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT        (0x0069)
+
+/****************************************************************************/
+/*  LAN values                                                              */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND      (0x0080)
+#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE        (0x0081)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR        (0x0082)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED      (0x0083)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR         (0x0084)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED       (0x0085)
+#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET        (0x0086)
+#define MPI_IOCSTATUS_LAN_CANCELED              (0x0087)
+
+
+/****************************************************************************/
+/*  IOCStatus flag to indicate that log info is available                   */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE   (0x8000)
+#define MPI_IOCSTATUS_MASK                      (0x7FFF)
+
+/****************************************************************************/
+/*  LogInfo Types                                                           */
+/****************************************************************************/
+
+#define MPI_IOCLOGINFO_TYPE_MASK                (0xF0000000)
+#define MPI_IOCLOGINFO_TYPE_NONE                (0x00)
+#define MPI_IOCLOGINFO_TYPE_SCSI                (0x01)
+#define MPI_IOCLOGINFO_TYPE_FC                  (0x02)
+#define MPI_IOCLOGINFO_LOG_DATA_MASK            (0x0FFFFFFF)
+
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_cnfg.h linux/drivers/message/fusion/lsi/mpi_cnfg.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_cnfg.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_cnfg.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,971 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_CNFG.H
+ *          Title:  MPI Config message, structures, and Pages
+ *  Creation Date:  July 27, 2000
+ *
+ *    MPI Version:  01.01.09
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added _PAGEVERSION definitions for all pages.
+ *                      Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ *                      fields to FC_DEVICE_0 page, updated the page version.
+ *                      Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ *                      SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ *                      and updated the page versions.
+ *                      Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ *                      page and updated the page version.
+ *                      Added Information field and _INFO_PARAMS_NEGOTIATED
+ *                      definitionto SCSI_DEVICE_0 page.
+ *  06-22-00  01.00.03  Removed batch controls from LAN_0 page and updated the
+ *                      page version.
+ *                      Added BucketsRemaining to LAN_1 page, redefined the
+ *                      state values, and updated the page version.
+ *                      Revised bus width definitions in SCSI_PORT_0,
+ *                      SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ *  06-30-00  01.00.04  Added MaxReplySize to LAN_1 page and updated the page
+ *                      version.
+ *                      Moved FC_DEVICE_0 PageAddress description to spec.
+ *  07-27-00  01.00.05  Corrected the SubsystemVendorID and SubsystemID field
+ *                      widths in IOC_0 page and updated the page version.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ *                      Port Page 2, FC Port Page 4, FC Port Page 5
+ *  11-15-00  01.01.02  Interim changes to match proposals
+ *  12-04-00  01.01.03  Config page changes to match MPI rev 1.00.01.
+ *  12-05-00  01.01.04  Modified config page actions.
+ *  01-09-01  01.01.05  Added defines for page address formats.
+ *                      Data size for Manufacturing pages 2 and 3 no longer
+ *                      defined here.
+ *                      Io Unit Page 2 size is fixed at 4 adapters and some
+ *                      flags were changed.
+ *                      SCSI Port Page 2 Device Settings modified.
+ *                      New fields added to FC Port Page 0 and some flags
+ *                      cleaned up.
+ *                      Removed impedance flash from FC Port Page 1.
+ *                      Added FC Port pages 6 and 7.
+ *  01-25-01  01.01.06  Added MaxInitiators field to FcPortPage0.
+ *  01-29-01  01.01.07  Changed some defines to make them 32 character unique.
+ *                      Added some LinkType defines for FcPortPage0.
+ *  02-20-01  01.01.08  Started using MPI_POINTER.
+ *  02-27-01  01.01.09  Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ *                      MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ *                      Added definitions and structures for IOC Page 2 and
+ *                      RAID Volume Page 2.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_CNFG_H
+#define MPI_CNFG_H
+
+
+/*****************************************************************************
+*
+*       C o n f i g    M e s s a g e    a n d    S t r u c t u r e s
+*
+*****************************************************************************/
+
+typedef struct _CONFIG_PAGE_HEADER
+{
+    U8                      PageVersion;
+    U8                      PageLength;
+    U8                      PageNumber;
+    U8                      PageType;
+} fCONFIG_PAGE_HEADER, MPI_POINTER PTR_CONFIG_PAGE_HEADER,
+  ConfigPageHeader_t, MPI_POINTER pConfigPageHeader_t;
+
+typedef union _CONFIG_PAGE_HEADER_UNION
+{
+   ConfigPageHeader_t  Struct;
+   U8                  Bytes[4];
+   U16                 Word16[2];
+   U32                 Word32;
+} ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion,
+  fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
+
+
+/****************************************************************************/
+/*  PageType field values                                                   */
+/****************************************************************************/
+#define MPI_CONFIG_PAGEATTR_READ_ONLY               (0x00)
+#define MPI_CONFIG_PAGEATTR_CHANGEABLE              (0x10)
+#define MPI_CONFIG_PAGEATTR_PERSISTENT              (0x20)
+#define MPI_CONFIG_PAGEATTR_MASK                    (0xF0)
+
+#define MPI_CONFIG_PAGETYPE_IO_UNIT                 (0x00)
+#define MPI_CONFIG_PAGETYPE_IOC                     (0x01)
+#define MPI_CONFIG_PAGETYPE_BIOS                    (0x02)
+#define MPI_CONFIG_PAGETYPE_SCSI_PORT               (0x03)
+#define MPI_CONFIG_PAGETYPE_SCSI_DEVICE             (0x04)
+#define MPI_CONFIG_PAGETYPE_FC_PORT                 (0x05)
+#define MPI_CONFIG_PAGETYPE_FC_DEVICE               (0x06)
+#define MPI_CONFIG_PAGETYPE_LAN                     (0x07)
+#define MPI_CONFIG_PAGETYPE_RAID_VOLUME             (0x08)
+#define MPI_CONFIG_PAGETYPE_MANUFACTURING           (0x09)
+#define MPI_CONFIG_PAGETYPE_MASK                    (0x0F)
+
+#define MPI_CONFIG_TYPENUM_MASK                     (0x0FFF)
+
+
+/****************************************************************************
+ *  PageAddres field values
+ ****************************************************************************/
+#define MPI_SCSI_PORT_PGAD_PORT_MASK                (0x000000FF)
+
+#define MPI_SCSI_DEVICE_TARGET_ID_MASK              (0x000000FF)
+#define MPI_SCSI_DEVICE_TARGET_ID_SHIFT             (0)
+#define MPI_SCSI_DEVICE_BUS_MASK                    (0x0000FF00)
+#define MPI_SCSI_DEVICE_BUS_SHIFT                   (8)
+
+#define MPI_SCSI_LUN_TARGET_ID_MASK                 (0x000000FF)
+#define MPI_SCSI_LUN_TARGET_ID_SHIFT                (0)
+#define MPI_SCSI_LUN_BUS_MASK                       (0x0000FF00)
+#define MPI_SCSI_LUN_BUS_SHIFT                      (8)
+#define MPI_SCSI_LUN_LUN_MASK                       (0x00FF0000)
+#define MPI_SCSI_LUN_LUN_SHIFT                      (16)
+
+#define MPI_FC_PORT_PGAD_PORT_MASK                  (0xF0000000)
+#define MPI_FC_PORT_PGAD_PORT_SHIFT                 (28)
+#define MPI_FC_PORT_PGAD_FORM_MASK                  (0x0F000000)
+#define MPI_FC_PORT_PGAD_FORM_INDEX                 (0x01000000)
+#define MPI_FC_PORT_PGAD_INDEX_MASK                 (0x0000FFFF)
+#define MPI_FC_PORT_PGAD_INDEX_SHIFT                (0)
+
+#define MPI_FC_DEVICE_PGAD_PORT_MASK                (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_PORT_SHIFT               (28)
+#define MPI_FC_DEVICE_PGAD_FORM_MASK                (0x0F000000)
+#define MPI_FC_DEVICE_PGAD_FORM_NEXT_DID            (0x00000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_MASK             (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT            (28)
+#define MPI_FC_DEVICE_PGAD_ND_DID_MASK              (0x00FFFFFF)
+#define MPI_FC_DEVICE_PGAD_ND_DID_SHIFT             (0)
+#define MPI_FC_DEVICE_PGAD_FORM_BUS_TID             (0x01000000)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_MASK              (0x0000FF00)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT             (8)
+#define MPI_FC_DEVICE_PGAD_BT_TID_MASK              (0x000000FF)
+#define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT             (0)
+
+
+/****************************************************************************/
+/*  Config Request Message                                                          */
+/****************************************************************************/
+typedef struct _MSG_CONFIG
+{
+    U8                      Action;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[8];
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     PageAddress;
+    SGE_IO_UNION            PageBufferSGE;
+} MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG,
+  Config_t, MPI_POINTER pConfig_t;
+
+
+/****************************************************************************/
+/*  Action field values                                                     */
+/****************************************************************************/
+#define MPI_CONFIG_ACTION_PAGE_HEADER               (0x00)
+/*#define MPI_CONFIG_ACTION_PAGE_READ                 (0x01) *//* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_READ_CURRENT         (0x01)
+/*#define MPI_CONFIG_ACTION_PAGE_WRITE                (0x02) *//* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT        (0x02)
+#define MPI_CONFIG_ACTION_PAGE_DEFAULT              (0x03)
+/*#define MPI_CONFIG_ACTION_PAGE_WRITE_COMMIT         (0x04) */ /* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM          (0x04)
+#define MPI_CONFIG_ACTION_PAGE_READ_DEFAULT         (0x05)
+#define MPI_CONFIG_ACTION_PAGE_READ_NVRAM           (0x06)
+
+
+/* Config Reply Message */
+typedef struct _MSG_CONFIG_REPLY
+{
+    U8                      Action;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+   fCONFIG_PAGE_HEADER      Header;
+} MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY,
+  ConfigReply_t, MPI_POINTER pConfigReply_t;
+
+
+
+/*****************************************************************************
+*
+*               C o n f i g u r a t i o n    P a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Manufacturing Config pages                                              */
+/****************************************************************************/
+#define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
+#define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
+#define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
+#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0035)
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U8                      ChipName[16];
+    U8                      ChipRevision[8];
+    U8                      BoardName[16];
+    U8                      BoardAssembly[16];
+    U8                      BoardTracerNumber[16];
+
+} fCONFIG_PAGE_MANUFACTURING_0, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_0,
+  ManufacturingPage0_t, MPI_POINTER pManufacturingPage0_t;
+
+#define MPI_MANUFACTURING0_PAGEVERSION                 (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U8                      VPD[256];
+} fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1,
+  ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t;
+
+#define MPI_MANUFACTURING1_PAGEVERSION                 (0x00)
+
+
+typedef struct _MPI_CHIP_REVISION_ID
+{
+    U16 DeviceID;
+    U8  PCIRevisionID;
+    U8  Reserved;
+} MPI_CHIP_REVISION_ID, MPI_POINTER PTR_MPI_CHIP_REVISION_ID,
+  MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t;
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_2
+{
+   fCONFIG_PAGE_HEADER                  Header;
+    MPI_CHIP_REVISION_ID                ChipId;
+    U32                                 HwSettings[1];
+} fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2,
+  ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t;
+
+#define MPI_MANUFACTURING2_PAGEVERSION                  (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_3
+{
+   fCONFIG_PAGE_HEADER                  Header;
+    MPI_CHIP_REVISION_ID                ChipId;
+    U32                                 Info[1];
+} fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3,
+  ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t;
+
+#define MPI_MANUFACTURING3_PAGEVERSION                  (0x00)
+
+
+/****************************************************************************/
+/*  IO Unit Config Pages                                                    */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IO_UNIT_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U64                     UniqueValue;
+} fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0,
+  IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t;
+
+#define MPI_IOUNITPAGE0_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_IO_UNIT_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+} fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
+  IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
+
+#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x00)
+
+#define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
+#define MPI_IOUNITPAGE1_SINGLE_FUNCTION                 (0x00000001)
+#define MPI_IOUNITPAGE1_MULTI_PATHING                   (0x00000002)
+#define MPI_IOUNITPAGE1_SINGLE_PATHING                  (0x00000000)
+
+#define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
+
+
+typedef struct _MPI_ADAPTER_INFO
+{
+    U8      PciBusNumber;
+    U8      PciDeviceAndFunctionNumber;
+    U16     AdapterFlags;
+} MPI_ADAPTER_INFO, MPI_POINTER PTR_MPI_ADAPTER_INFO,
+  MpiAdapterInfo_t, MPI_POINTER pMpiAdapterInfo_t;
+
+#define MPI_ADAPTER_INFO_FLAGS_EMBEDDED                 (0x0001)
+#define MPI_ADAPTER_INFO_FLAGS_INIT_STATUS              (0x0002)
+
+typedef struct _CONFIG_PAGE_IO_UNIT_2
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U32                     BiosVersion;
+    MPI_ADAPTER_INFO        AdapterOrder[4];
+} fCONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2,
+  IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t;
+
+#define MPI_IOUNITPAGE2_PAGEVERSION                     (0x00)
+
+#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE              (0x00000001)
+#define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR            (0x00000002)
+#define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE            (0x00000004)
+#define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE       (0x00000008)
+#define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40          (0x00000010)
+
+
+/****************************************************************************/
+/*  IOC Config Pages                                                        */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IOC_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     TotalNVStore;
+    U32                     FreeNVStore;
+    U16                     VendorID;
+    U16                     DeviceID;
+    U8                      RevisionID;
+    U8                      Reserved[3];
+    U32                     ClassCode;
+    U16                     SubsystemVendorID;
+    U16                     SubsystemID;
+} fCONFIG_PAGE_IOC_0, MPI_POINTER PTR_CONFIG_PAGE_IOC_0,
+  IOCPage0_t, MPI_POINTER pIOCPage0_t;
+
+#define MPI_IOCPAGE0_PAGEVERSION                        (0x01)
+
+typedef struct _CONFIG_PAGE_IOC_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U32                     CoalescingTimeout;
+    U8                      CoalescingDepth;
+    U8                      Reserved[3];
+} fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1,
+  IOCPage1_t, MPI_POINTER pIOCPage1_t;
+
+#define MPI_IOCPAGE1_PAGEVERSION                        (0x00)
+
+#define MPI_IOCPAGE1_REPLY_COALESCING                   (0x00000001)
+
+typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
+{
+    U8                      VolumeTargetID;
+    U8                      VolumeBus;
+    U16                     Reserved;
+    U8                      VolumeVersionMinor;
+    U8                      VolumeVersionMajor;
+    U8                      VolumeRaidType;
+    U8                      Reserved1;
+} fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
+  ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
+
+typedef struct _CONFIG_PAGE_IOC_2
+{
+   fCONFIG_PAGE_HEADER          Header;
+    U32                         CapabilitiesFlags;
+    U8                          NumActiveVolumes;
+    U8                          MaxVolumes;
+    U16                         Reserved;
+   fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[1];
+} fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
+  IOCPage2_t, MPI_POINTER pIOCPage2_t;
+
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x00)
+
+/* IOC Page 2 Capabilities flags */
+
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT           (0x00000001)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT           (0x00000002)
+#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT       (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT           (0x00000008)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT          (0x00000010)
+
+/* IOC Page 2 Volume RAID Type values */
+
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_0                    (0x00)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_1                    (0x01)
+#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR                (0x02)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_5                    (0x05)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_10                   (0x0A)
+
+
+/****************************************************************************/
+/*  SCSI Port Config Pages                                                  */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Capabilities;
+    U32                     PhysicalInterface;
+} fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0,
+  SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t;
+
+#define MPI_SCSIPORTPAGE0_PAGEVERSION                   (0x01)
+
+#define MPI_SCSIPORTPAGE0_CAP_IU                        (0x00000001)
+#define MPI_SCSIPORTPAGE0_CAP_DT                        (0x00000002)
+#define MPI_SCSIPORTPAGE0_CAP_QAS                       (0x00000004)
+#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS          (0x00000008)
+#define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK      (0x0000FF00)
+#define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
+#define MPI_SCSIPORTPAGE0_CAP_WIDE                      (0x20000000)
+#define MPI_SCSIPORTPAGE0_CAP_AIP                       (0x80000000)
+
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK          (0x00000003)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD                (0x01)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE                 (0x02)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD                (0x03)
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Configuration;
+} fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
+  SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
+
+#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x01)
+
+#define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
+#define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
+
+typedef struct _MPI_DEVICE_INFO
+{
+    U8      Timeout;
+    U8      SyncFactor;
+    U16     DeviceFlags;
+} MPI_DEVICE_INFO, MPI_POINTER PTR_MPI_DEVICE_INFO,
+  MpiDeviceInfo_t, MPI_POINTER pMpiDeviceInfo_t;
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_2
+{
+   fCONFIG_PAGE_HEADER  Header;
+    U32                 PortFlags;
+    U32                 PortSettings;
+    MPI_DEVICE_INFO     DeviceSettings[16];
+} fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2,
+  SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t;
+
+#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x01)
+
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW       (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE          (0x00000002)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET       (0x00000004)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS          (0x00000008)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE    (0x00000010)
+
+#define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK                 (0x0000000F)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA                (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA             (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_INIT_HBA                (0x00000010)
+#define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA                  (0x00000020)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA             (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA              (0x000000C0)
+#define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK            (0x00000F00)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS    (0x00003000)
+#define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS         (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS         (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS          (0x00000003)
+
+#define MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE          (0x00000001)
+#define MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE             (0x00000002)
+#define MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE            (0x00000004)
+#define MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE           (0x00000008)
+#define MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE               (0x00000010)
+#define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE                (0x00000020)
+
+
+/****************************************************************************/
+/*  SCSI Target Device Config Pages                                         */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     NegotiatedParameters;
+    U32                     Information;
+} fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
+  SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
+
+#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x01)
+
+#define MPI_SCSIDEVPAGE0_NP_IU                          (0x00000001)
+#define MPI_SCSIDEVPAGE0_NP_DT                          (0x00000002)
+#define MPI_SCSIDEVPAGE0_NP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS            (0x00000008)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
+#define MPI_SCSIDEVPAGE0_NP_AIP                         (0x80000000)
+
+#define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED         (0x00000001)
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     RequestedParameters;
+    U32                     DomainValidation;
+    U32                     Configuration;
+} fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
+  SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
+
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x01)
+
+#define MPI_SCSIDEVPAGE1_RP_IU                          (0x00000001)
+#define MPI_SCSIDEVPAGE1_RP_DT                          (0x00000002)
+#define MPI_SCSIDEVPAGE1_RP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS            (0x00000008)
+#define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE1_RP_WIDE                        (0x20000000)
+#define MPI_SCSIDEVPAGE1_RP_AIP                         (0x80000000)
+
+#define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK     (0x00000003)
+#define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK           (0x00000300)
+
+#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED               (0x00000001)
+
+/****************************************************************************/
+/*  FC Port Config Pages                                                    */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_PORT_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U8                      MPIPortNumber;
+    U8                      LinkType;
+    U8                      PortState;
+    U8                      Reserved;
+    U32                     PortIdentifier;
+    U64                     WWNN;
+    U64                     WWPN;
+    U32                     SupportedServiceClass;
+    U32                     SupportedSpeeds;
+    U32                     CurrentSpeed;
+    U32                     MaxFrameSize;
+    U64                     FabricWWNN;
+    U64                     FabricWWPN;
+    U32                     DiscoveredPortsCount;
+    U32                     MaxInitiators;
+} fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0,
+  FCPortPage0_t, MPI_POINTER pFCPortPage0_t;
+
+#define MPI_FCPORTPAGE0_PAGEVERSION                     (0x01)
+
+#define MPI_FCPORTPAGE0_FLAGS_PROT_MASK                 (0x0000000F)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT             (MPI_PORTFACTS_PROTOCOL_INITIATOR)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_TARG             (MPI_PORTFACTS_PROTOCOL_TARGET)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LAN                  (MPI_PORTFACTS_PROTOCOL_LAN)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LOGBUSADDR           (MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)
+
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED      (0x00000010)
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED       (0x00000020)
+#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000030)
+
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK          (0x00000700)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT     (0x00000000)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP       (0x00000100)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT      (0x00000200)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP        (0x00000300)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT            (0x00000700)
+
+#define MPI_FCPORTPAGE0_LTYPE_RESERVED                  (0x00)
+#define MPI_FCPORTPAGE0_LTYPE_OTHER                     (0x01)
+#define MPI_FCPORTPAGE0_LTYPE_UNKNOWN                   (0x02)
+#define MPI_FCPORTPAGE0_LTYPE_COPPER                    (0x03)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1300               (0x04)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1500               (0x05)
+#define MPI_FCPORTPAGE0_LTYPE_50_LASER_MULTI            (0x06)
+#define MPI_FCPORTPAGE0_LTYPE_50_LED_MULTI              (0x07)
+#define MPI_FCPORTPAGE0_LTYPE_62_LASER_MULTI            (0x08)
+#define MPI_FCPORTPAGE0_LTYPE_62_LED_MULTI              (0x09)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_LONG_WAVE           (0x0A)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_SHORT_WAVE          (0x0B)
+#define MPI_FCPORTPAGE0_LTYPE_LASER_SHORT_WAVE          (0x0C)
+#define MPI_FCPORTPAGE0_LTYPE_LED_SHORT_WAVE            (0x0D)
+#define MPI_FCPORTPAGE0_LTYPE_1300_LONG_WAVE            (0x0E)
+#define MPI_FCPORTPAGE0_LTYPE_1500_LONG_WAVE            (0x0F)
+
+#define MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN               (0x01)      /*(SNIA)HBA_PORTSTATE_UNKNOWN       1 Unknown */
+#define MPI_FCPORTPAGE0_PORTSTATE_ONLINE                (0x02)      /*(SNIA)HBA_PORTSTATE_ONLINE        2 Operational */
+#define MPI_FCPORTPAGE0_PORTSTATE_OFFLINE               (0x03)      /*(SNIA)HBA_PORTSTATE_OFFLINE       3 User Offline */
+#define MPI_FCPORTPAGE0_PORTSTATE_BYPASSED              (0x04)      /*(SNIA)HBA_PORTSTATE_BYPASSED      4 Bypassed */
+#define MPI_FCPORTPAGE0_PORTSTATE_DIAGNOST              (0x05)      /*(SNIA)HBA_PORTSTATE_DIAGNOSTICS   5 In diagnostics mode */
+#define MPI_FCPORTPAGE0_PORTSTATE_LINKDOWN              (0x06)      /*(SNIA)HBA_PORTSTATE_LINKDOWN      6 Link Down */
+#define MPI_FCPORTPAGE0_PORTSTATE_ERROR                 (0x07)      /*(SNIA)HBA_PORTSTATE_ERROR         7 Port Error */
+#define MPI_FCPORTPAGE0_PORTSTATE_LOOPBACK              (0x08)      /*(SNIA)HBA_PORTSTATE_LOOPBACK      8 Loopback */
+
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_1                 (0x00000001)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_2                 (0x00000002)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_3                 (0x00000004)
+
+#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED             (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1  1 GBit/sec  */
+#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED             (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2  2 GBit/sec  */
+#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED            (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */
+
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT             MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT             MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT            MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U64                     NoSEEPROMWWNN;
+    U64                     NoSEEPROMWWPN;
+    U8                      HardALPA;
+    U8                      LinkConfig;
+    U8                      TopologyConfig;
+    U8                      Reserved;
+} fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
+  FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
+
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x01)
+
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
+
+#define MPI_FCPORTPAGE1_FLAGS_PROT_MASK                 (0xF0000000)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT                (28)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT             ((U32)MPI_PORTFACTS_PROTOCOL_INITIATOR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG             ((U32)MPI_PORTFACTS_PROTOCOL_TARGET << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LAN                  ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR           ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+
+#define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED              (0xFF)
+
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK              (0x0F)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG              (0x00)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG              (0x01)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG              (0x02)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG             (0x03)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO              (0x0F)
+
+#define MPI_FCPORTPAGE1_TOPOLGY_MASK                    (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT                  (0x01)
+#define MPI_FCPORTPAGE1_TOPOLGY_NPORT                   (0x02)
+#define MPI_FCPORTPAGE1_TOPOLGY_AUTO                    (0x0F)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_2
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U8                      NumberActive;
+    U8                      ALPA[126];
+    U8                      Reserved;
+} fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2,
+  FCPortPage2_t, MPI_POINTER pFCPortPage2_t;
+
+#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x00)
+
+
+typedef struct _FC_PORT_PERSISTENT
+{
+    U64                     WWNN;
+    U64                     WWPN;
+    U8                      TargetID;
+    U8                      Bus;
+    U16                     Flags;
+} FC_PORT_PERSISTENT, MPI_POINTER PTR_FC_PORT_PERSISTENT,
+  PersistentData_t, MPI_POINTER pPersistentData_t;
+
+#define MPI_PERSISTENT_FLAGS_SHIFT                      (16)
+#define MPI_PERSISTENT_FLAGS_ENTRY_VALID                (0x0001)
+#define MPI_PERSISTENT_FLAGS_SCAN_ID                    (0x0002)
+#define MPI_PERSISTENT_FLAGS_SCAN_LUNS                  (0x0004)
+#define MPI_PERSISTENT_FLAGS_BOOT_DEVICE                (0x0008)
+
+typedef struct _CONFIG_PAGE_FC_PORT_3
+{
+   fCONFIG_PAGE_HEADER      Header;
+    FC_PORT_PERSISTENT      Entry[1];
+} fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3,
+  FCPortPage3_t, MPI_POINTER pFCPortPage3_t;
+
+#define MPI_FCPORTPAGE3_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_4
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     PortFlags;
+    U32                     PortSettings;
+} fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4,
+  FCPortPage4_t, MPI_POINTER pFCPortPage4_t;
+
+#define MPI_FCPORTPAGE4_PAGEVERSION                     (0x00)
+
+#define MPI_FCPORTPAGE4_PORT_FLAGS_ALTERNATE_CHS        (0x00000008)
+
+#define MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA              (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA           (0x00000000)
+#define MPI_FCPORTPAGE4_PORT_BIOS_INIT_HBA              (0x00000010)
+#define MPI_FCPORTPAGE4_PORT_OS_INIT_HBA                (0x00000020)
+#define MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA           (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_REMOVABLE_MEDIA            (0x000000C0)
+#define MPI_FCPORTPAGE4_PORT_SPINUP_DELAY_MASK          (0x00000F00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO
+{
+    U8      Flags;
+    U8      AliasAlpa;
+    U16     Reserved;
+    U64     AliasWWNN;
+    U64     AliasWWPN;
+} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+  FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
+
+typedef struct _CONFIG_PAGE_FC_PORT_5
+{
+   fCONFIG_PAGE_HEADER                  Header;
+   fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[1];
+} fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
+  FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
+
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x00)
+
+#define MPI_FCPORTPAGE5_FLAGS_ALIAS_ALPA_VALID          (0x01)
+#define MPI_FCPORTPAGE5_FLAGS_ALIAS_WWN_VALID           (0x02)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_6
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Reserved;
+    U64                     TimeSinceReset;
+    U64                     TxFrames;
+    U64                     RxFrames;
+    U64                     TxWords;
+    U64                     RxWords;
+    U64                     LipCount;
+    U64                     NosCount;
+    U64                     ErrorFrames;
+    U64                     DumpedFrames;
+    U64                     LinkFailureCount;
+    U64                     LossOfSyncCount;
+    U64                     LossOfSignalCount;
+    U64                     PrimativeSeqErrCount;
+    U64                     InvalidTxWordCount;
+    U64                     InvalidCrcCount;
+    U64                     FcpInitiatorIoCount;
+} fCONFIG_PAGE_FC_PORT_6, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_6,
+  FCPortPage6_t, MPI_POINTER pFCPortPage6_t;
+
+#define MPI_FCPORTPAGE6_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_7
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Reserved;
+    U8                      PortSymbolicName[256];
+} fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7,
+  FCPortPage7_t, MPI_POINTER pFCPortPage7_t;
+
+#define MPI_FCPORTPAGE7_PAGEVERSION                     (0x00)
+
+
+/****************************************************************************/
+/*  FC Device Config Pages                                                  */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_DEVICE_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U64                     WWNN;
+    U64                     WWPN;
+    U32                     PortIdentifier;
+    U8                      Protocol;
+    U8                      Flags;
+    U16                     BBCredit;
+    U16                     MaxRxFrameSize;
+    U8                      Reserved1;
+    U8                      PortNumber;
+    U8                      FcPhLowestVersion;
+    U8                      FcPhHighestVersion;
+    U8                      CurrentTargetID;
+    U8                      CurrentBus;
+} fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0,
+  FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t;
+
+#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x02)
+
+#define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID    (0x01)
+
+#define MPI_FC_DEVICE_PAGE0_PROT_IP                     (0x01)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET             (0x02)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR          (0x04)
+
+#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK              (MPI_FC_DEVICE_PGAD_PORT_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK              (MPI_FC_DEVICE_PGAD_FORM_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID          (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID           (MPI_FC_DEVICE_PGAD_FORM_BUS_TID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK               (MPI_FC_DEVICE_PGAD_ND_DID_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK               (MPI_FC_DEVICE_PGAD_BT_BUS_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT              (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
+#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK               (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
+
+
+/****************************************************************************/
+/*  RAID Volume Config Pages                                                  */
+/****************************************************************************/
+
+typedef struct _RAIDVOL2_EM_PHYS_ID
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      IocNumber;
+    U8                      PhysDiskNumber;
+    U8                      Reserved[8];
+    U8                      PhysicalDiskIdentifier[16];
+    U8                      ProductId[16];
+    U8                      InfoOffset0;
+    U8                      InfoSize0;
+    U8                      InfoOffset1;
+    U8                      InfoSize1;
+    U8                      Info[32];
+} RAIDVOL2_EM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_EM_PHYS_ID,
+  RaidVol2EmPhysicalID_t, MPI_POINTER pRaidVol2EmPhysicalID_t;
+
+typedef struct _RAIDVOL2_EM_DISK_INFO
+{
+    U32                     DiskStatus;
+    U32                     DeviceSettings;
+    U16                     ErrorCount;
+    U16                     Reserved;
+    U8                      ErrorCdbByte;
+    U8                      ErrorSenseKey;
+    U8                      ErrorASC;
+    U8                      ErrorASCQ;
+    U16                     SmartCount;
+    U8                      SmartASC;
+    U8                      SmartASCQ;
+} RAIDVOL2_EM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_EM_DISK_INFO,
+  RaidVol2EmDiskInfo_t, MPI_POINTER pRaidVol2EmDiskInfo_t;
+
+/* RAID Volume 2 EM Physical Disk DiskStatus flags */
+
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_PRIMARY              (0x00000001)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_SECONDARY            (0x00000002)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_HOT_SPARE            (0x00000004)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_OUT_OF_SYNC          (0x00000008)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_OFFLINE              (0x00000010)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_NOT_RESPONDING       (0x00000020)
+
+typedef struct _RAIDVOL2_EM_PHYSICAL_DISK
+{
+    RAIDVOL2_EM_PHYS_ID     Id;
+    RAIDVOL2_EM_DISK_INFO   Info;
+} RAIDVOL2_EM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_EM_PHYSICAL_DISK,
+  RaidVol2EmPhysicalDisk_t, MPI_POINTER pRaidVol2EmPhysicalDisk_t;
+
+#define MPI_RAIDVOLPAGE2_MAX_DISKS                      (3)
+
+typedef struct _CONFIG_PAGE_RAID_VOL_2
+{
+   fCONFIG_PAGE_HEADER          Header;
+    U32                         VolumeStatus;
+    U32                         VolumeSettings;
+    U32                         Reserved;
+    U64                         MaxLba;
+    U32                         BlockSize;
+    U8                          InquirySize;
+    U8                          NumPhysicalDisks;
+    U16                         Reserved1;
+    U8                          InquiryData[56];
+    RAIDVOL2_EM_PHYSICAL_DISK   EMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS];
+} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2,
+  RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t;
+
+#define MPI_RAIDVOLPAGE2_PAGEVERSION                    (0x00)
+
+/* RAID Volume Page 2 VolumeStatus defines */
+
+#define MPI_RAIDVOLPAGE2_STATUS_ENABLED                 (0x00000001)
+#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED                (0x00000002)
+#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS      (0x00000004)
+#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED                (0x00000008)
+
+/* RAID Volume Page 2 VolumeSettings defines */
+
+#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE   (0x00000001)
+#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART       (0x00000002)
+#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE         (0x00000004)
+
+
+/****************************************************************************/
+/* LAN Config Pages                                                         */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_LAN_0
+{
+    ConfigPageHeader_t      Header;
+    U16                     TxRxModes;
+    U16                     Reserved;
+    U32                     PacketPrePad;
+} fCONFIG_PAGE_LAN_0, MPI_POINTER PTR_CONFIG_PAGE_LAN_0,
+  LANPage0_t, MPI_POINTER pLANPage0_t;
+
+#define MPI_LAN_PAGE0_PAGEVERSION                       (0x01)
+
+#define MPI_LAN_PAGE0_RETURN_LOOPBACK                   (0x0000)
+#define MPI_LAN_PAGE0_SUPPRESS_LOOPBACK                 (0x0001)
+#define MPI_LAN_PAGE0_LOOPBACK_MASK                     (0x0001)
+
+typedef struct _CONFIG_PAGE_LAN_1
+{
+    ConfigPageHeader_t      Header;
+    U16                     Reserved;
+    U8                      CurrentDeviceState;
+    U8                      Reserved1;
+    U32                     MinPacketSize;
+    U32                     MaxPacketSize;
+    U32                     HardwareAddressLow;
+    U32                     HardwareAddressHigh;
+    U32                     MaxWireSpeedLow;
+    U32                     MaxWireSpeedHigh;
+    U32                     BucketsRemaining;
+    U32                     MaxReplySize;
+    U32                     NegWireSpeedHigh;
+    U32                     NegWireSpeedLow;
+} fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1,
+  LANPage1_t, MPI_POINTER pLANPage1_t;
+
+#define MPI_LAN_PAGE1_PAGEVERSION                       (0x03)
+
+#define MPI_LAN_PAGE1_DEV_STATE_RESET                   (0x00)
+#define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL             (0x01)
+
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_fc.h linux/drivers/message/fusion/lsi/mpi_fc.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_fc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_fc.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,350 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_FC.H
+ *          Title:  MPI Fibre Channel messages and structures
+ *  Creation Date:  June 12, 2000
+ *
+ *    MPI Version:  01.01.05
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added _MSG_FC_ABORT_REPLY structure.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added messages for Common Transport Send and
+ *                      Primitive Send.
+ *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *                      and modified the FcPrimitiveSend flags.
+ *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
+ *                      field.
+ *                      Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ *                      FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_FC_H
+#define MPI_FC_H
+
+
+/*****************************************************************************
+*
+*        F C    T a r g e t    M o d e    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Link Service Buffer Post messages                                        */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REQUEST
+{
+    U8                      BufferPostFlags;    /* 00h */
+    U8                      BufferCount;        /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved;           /* 04h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    SGE_TRANS_SIMPLE_UNION  SGL;
+} MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+ MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+  LinkServiceBufferPostRequest_t, MPI_POINTER pLinkServiceBufferPostRequest_t;
+
+#define LINK_SERVICE_BUFFER_POST_FLAGS_PORT_MASK (0x01)
+
+typedef struct _WWNFORMAT
+{
+    U32                     PortNameHigh;       /* 00h */
+    U32                     PortNameLow;        /* 04h */
+    U32                     NodeNameHigh;       /* 08h */
+    U32                     NodeNameLow;        /* 0Ch */
+} WWNFORMAT,
+  WwnFormat_t;
+
+/* Link Service Buffer Post Reply */
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REPLY
+{
+    U8                      Flags;              /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved2;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferLength;     /* 14h */
+    U32                     TransactionContext; /* 18h */
+    U32                     Rctl_Did;           /* 1Ch */
+    U32                     Csctl_Sid;          /* 20h */
+    U32                     Type_Fctl;          /* 24h */
+    U16                     SeqCnt;             /* 28h */
+    U8                      Dfctl;              /* 2Ah */
+    U8                      SeqId;              /* 2Bh */
+    U16                     Rxid;               /* 2Ch */
+    U16                     Oxid;               /* 2Eh */
+    U32                     Parameter;          /* 30h */
+    WWNFORMAT               Wwn;                /* 34h */
+} MSG_LINK_SERVICE_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY,
+  LinkServiceBufferPostReply_t, MPI_POINTER pLinkServiceBufferPostReply_t;
+
+#define MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED    (0x80)
+
+#define MPI_FC_DID_MASK                             (0x00FFFFFF)
+#define MPI_FC_DID_SHIFT                            (0)
+#define MPI_FC_RCTL_MASK                            (0xFF000000)
+#define MPI_FC_RCTL_SHIFT                           (24)
+#define MPI_FC_SID_MASK                             (0x00FFFFFF)
+#define MPI_FC_SID_SHIFT                            (0)
+#define MPI_FC_CSCTL_MASK                           (0xFF000000)
+#define MPI_FC_CSCTL_SHIFT                          (24)
+#define MPI_FC_FCTL_MASK                            (0x00FFFFFF)
+#define MPI_FC_FCTL_SHIFT                           (0)
+#define MPI_FC_TYPE_MASK                            (0xFF000000)
+#define MPI_FC_TYPE_SHIFT                           (24)
+
+/* obsolete name for the above */
+#define FCP_TARGET_DID_MASK                         (0x00FFFFFF)
+#define FCP_TARGET_DID_SHIFT                        (0)
+#define FCP_TARGET_RCTL_MASK                        (0xFF000000)
+#define FCP_TARGET_RCTL_SHIFT                       (24)
+#define FCP_TARGET_SID_MASK                         (0x00FFFFFF)
+#define FCP_TARGET_SID_SHIFT                        (0)
+#define FCP_TARGET_CSCTL_MASK                       (0xFF000000)
+#define FCP_TARGET_CSCTL_SHIFT                      (24)
+#define FCP_TARGET_FCTL_MASK                        (0x00FFFFFF)
+#define FCP_TARGET_FCTL_SHIFT                       (0)
+#define FCP_TARGET_TYPE_MASK                        (0xFF000000)
+#define FCP_TARGET_TYPE_SHIFT                       (24)
+
+
+/****************************************************************************/
+/* Link Service Response messages                                           */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_RSP_REQUEST
+{
+    U8                      RspFlags;           /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Rctl_Did;           /* 0Ch */
+    U32                     Csctl_Sid;          /* 10h */
+    U32                     Type_Fctl;          /* 14h */
+    U16                     SeqCnt;             /* 18h */
+    U8                      Dfctl;              /* 1Ah */
+    U8                      SeqId;              /* 1Bh */
+    U16                     Rxid;               /* 1Ch */
+    U16                     Oxid;               /* 1Eh */
+    U32                     Parameter;          /* 20h */
+    SGE_SIMPLE_UNION        SGL;                /* 24h */
+} MSG_LINK_SERVICE_RSP_REQUEST, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REQUEST,
+  LinkServiceRspRequest_t, MPI_POINTER pLinkServiceRspRequest_t;
+
+#define LINK_SERVICE_RSP_FLAGS_IMMEDIATE        (0x80)
+#define LINK_SERVICE_RSP_FLAGS_PORT_MASK        (0x01)
+
+
+/* Link Service Response Reply  */
+typedef struct _MSG_LINK_SERVICE_RSP_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     InitiatorIndex;     /* 14h */
+} MSG_LINK_SERVICE_RSP_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REPLY,
+  LinkServiceRspReply_t, MPI_POINTER pLinkServiceRspReply_t;
+
+
+/****************************************************************************/
+/* Extended Link Service Send messages                                      */
+/****************************************************************************/
+
+typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U32                     MsgFlags_Did;       /* 04h */
+    U32                     MsgContext;         /* 08h */
+    U32                     ElsCommandCode;     /* 0Ch */
+    SGE_SIMPLE_UNION        SGL;                /* 10h */
+} MSG_EXLINK_SERVICE_SEND_REQUEST, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REQUEST,
+  ExLinkServiceSendRequest_t, MPI_POINTER pExLinkServiceSendRequest_t;
+
+#define EX_LINK_SERVICE_SEND_DID_MASK           (0x00FFFFFF)
+#define EX_LINK_SERVICE_SEND_DID_SHIFT          (0)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_MASK      (0xFF000000)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_SHIFT     (24)
+
+
+/* Extended Link Service Send Reply */
+typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_EXLINK_SERVICE_SEND_REPLY, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REPLY,
+  ExLinkServiceSendReply_t, MPI_POINTER pExLinkServiceSendReply_t;
+
+/****************************************************************************/
+/* FC Abort messages                                                        */
+/****************************************************************************/
+
+typedef struct _MSG_FC_ABORT_REQUEST
+{
+    U8                      AbortFlags;         /* 00h */
+    U8                      AbortType;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     TransactionContextToAbort;  /* 0Ch */
+} MSG_FC_ABORT_REQUEST, MPI_POINTER PTR_MSG_FC_ABORT_REQUEST,
+  FcAbortRequest_t, MPI_POINTER pFcAbortRequest_t;
+
+#define FC_ABORT_FLAG_PORT_MASK                 (0x01)
+
+#define FC_ABORT_TYPE_ALL_FC_BUFFERS            (0x00)
+#define FC_ABORT_TYPE_EXACT_FC_BUFFER           (0x01)
+#define FC_ABORT_TYPE_CT_SEND_REQUEST           (0x02)
+#define FC_ABORT_TYPE_EXLINKSEND_REQUEST        (0x03)
+
+/* FC Abort Reply */
+typedef struct _MSG_FC_ABORT_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_FC_ABORT_REPLY, MPI_POINTER PTR_MSG_FC_ABORT_REPLY,
+  FcAbortReply_t, MPI_POINTER pFcAbortReply_t;
+
+
+/****************************************************************************/
+/* FC Common Transport Send messages                                        */
+/****************************************************************************/
+
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U32                     MsgFlags_Did;       /* 04h */
+    U32                     MsgContext;         /* 08h */
+    U16                     CTCommandCode;      /* 0Ch */
+    U8                      FsType;             /* 0Eh */
+    U8                      Reserved1;          /* 0Fh */
+    SGE_SIMPLE_UNION        SGL;                /* 10h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+ MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+  FcCommonTransportSendRequest_t, MPI_POINTER pFcCommonTransportSendRequest_t;
+
+#define MPI_FC_CT_SEND_DID_MASK                 (0x00FFFFFF)
+#define MPI_FC_CT_SEND_DID_SHIFT                (0)
+#define MPI_FC_CT_SEND_MSGFLAGS_MASK            (0xFF000000)
+#define MPI_FC_CT_SEND_MSGFLAGS_SHIFT           (24)
+
+
+/* FC Common Transport Send Reply */
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REPLY, MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REPLY,
+  FcCommonTransportSendReply_t, MPI_POINTER pFcCommonTransportSendReply_t;
+
+
+/****************************************************************************/
+/* FC Primitive Send messages                                               */
+/****************************************************************************/
+
+typedef struct _MSG_FC_PRIMITIVE_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      FcPrimitive[4];     /* 0Ch */
+} MSG_FC_PRIMITIVE_SEND_REQUEST, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REQUEST,
+  FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t;
+
+#define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK       (0x01)
+#define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND       (0x08)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE       (0x10)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_AROUND     (0x20)
+#define MPI_FC_PRIM_SEND_FLAGS_UNTIL_FULL      (0x40)
+#define MPI_FC_PRIM_SEND_FLAGS_FOREVER         (0x80)
+
+/* FC Primitive Send Reply */
+typedef struct _MSG_FC_PRIMITIVE_SEND_REPLY
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_FC_PRIMITIVE_SEND_REPLY, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REPLY,
+  FcPrimitiveSendReply_t, MPI_POINTER pFcPrimitiveSendReply_t;
+
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_history.txt linux/drivers/message/fusion/lsi/mpi_history.txt
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_history.txt	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_history.txt	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,237 @@
+
+ ==============================
+ MPI Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2001 LSI Logic Corporation.
+
+ ---------------------------------------
+ Header Set Release Version:    01.01.08
+ Header Set Release Date:       02-27-01
+ ---------------------------------------
+
+ Filename               Current version     Prior version
+ ----------             ---------------     -------------
+ mpi.h                  01.01.06            01.01.05
+ mpi_ioc.h              01.01.05            01.01.04
+ mpi_cnfg.h             01.01.09            01.01.08
+ mpi_init.h             01.01.03            01.01.03
+ mpi_targ.h             01.01.03            01.01.03
+ mpi_fc.h               01.01.05            01.01.05
+ mpi_lan.h              01.01.02            01.01.02
+ mpi_raid.h             01.01.01            none
+ mpi_type.h             01.01.02            01.01.02
+ mpi_history.txt        01.01.08            01.01.07
+
+
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+
+mpi.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ *  06-06-00  01.00.01  Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ *  06-22-00  01.00.02  Added MPI_IOCSTATUS_LAN_ definitions.
+ *                      Removed LAN_SUSPEND function definition.
+ *                      Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ *  06-30-00  01.00.03  Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ *                      Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ *  07-27-00  01.00.04  Added MPI_FAULT_ definitions.
+ *                      Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ *                      Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ *                      Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added new function codes.
+ *  01-09-01  01.01.03  Added more definitions to the system interface section
+ *                      Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ *  01-25-01  01.01.04  Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *                      Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ *                      MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ *                      Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ *  02-27-01  01.01.06  Removed MPI_HOST_INDEX_REGISTER define.
+ *                      Added function codes for RAID.
+ *  --------------------------------------------------------------------------
+
+mpi_ioc.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added _MSG_IOC_INIT_REPLY structure.
+ *  06-06-00  01.00.01  Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ *  06-12-00  01.00.02  Added _MSG_PORT_ENABLE_REPLY structure.
+ *                      Added _MSG_EVENT_ACK_REPLY structure.
+ *                      Added _MSG_FW_DOWNLOAD_REPLY structure.
+ *                      Added _MSG_TOOLBOX_REPLY structure.
+ *  06-30-00  01.00.03  Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ *  07-27-00  01.00.04  Added _EVENT_DATA structure definitions for _SCSI,
+ *                      _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ *  08-11-00  01.00.05  Switched positions of MsgLength and Function fields in
+ *                      _MSG_EVENT_ACK_REPLY structure to match specification.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added a value for Manufacturer to WhoInit
+ *  12-04-00  01.01.02  Modified IOCFacts reply, added FWUpload messages, and
+ *                      removed toolbox message.
+ *  01-09-01  01.01.03  Added event enabled and disabled defines.
+ *                      Added structures for FwHeader and DataHeader.
+ *                      Added ImageType to FwUpload reply.
+ *  02-20-01  01.01.04  Started using MPI_POINTER.
+ *  02-27-01  01.01.05  Added event for RAID status change and its event data.
+ *                      Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ *  --------------------------------------------------------------------------
+
+mpi_cnfg.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added _PAGEVERSION definitions for all pages.
+ *                      Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ *                      fields to FC_DEVICE_0 page, updated the page version.
+ *                      Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ *                      SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ *                      and updated the page versions.
+ *                      Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ *                      page and updated the page version.
+ *                      Added Information field and _INFO_PARAMS_NEGOTIATED
+ *                      definitionto SCSI_DEVICE_0 page.
+ *  06-22-00  01.00.03  Removed batch controls from LAN_0 page and updated the
+ *                      page version.
+ *                      Added BucketsRemaining to LAN_1 page, redefined the
+ *                      state values, and updated the page version.
+ *                      Revised bus width definitions in SCSI_PORT_0,
+ *                      SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ *  06-30-00  01.00.04  Added MaxReplySize to LAN_1 page and updated the page
+ *                      version.
+ *                      Moved FC_DEVICE_0 PageAddress description to spec.
+ *  07-27-00  01.00.05  Corrected the SubsystemVendorID and SubsystemID field
+ *                      widths in IOC_0 page and updated the page version.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ *                      Port Page 2, FC Port Page 4, FC Port Page 5
+ *  12-04-00  01.01.03  Config page changes to match MPI rev 1.00.01.
+ *  12-05-00  01.01.04  Modified config page actions.
+ *  01-09-01  01.01.05  Added defines for page address formats.
+ *                      Data size for Manufacturing pages 2 and 3 no longer
+ *                      defined here.
+ *                      Io Unit Page 2 size is fixed at 4 adapters and some
+ *                      flags were changed.
+ *                      SCSI Port Page 2 Device Settings modified.
+ *                      New fields added to FC Port Page 0 and some flags
+ *                      cleaned up.
+ *                      Removed impedance flash from FC Port Page 1.
+ *                      Added FC Port pages 6 and 7.
+ *  01-25-01  01.01.06  Added MaxInitiators field to FcPortPage0.
+ *  01-29-01  01.01.07  Changed some defines to make them 32 character unique.
+ *                      Added some LinkType defines for FcPortPage0.
+ *  02-20-01  01.01.08  Started using MPI_POINTER.
+ *  02-27-01  01.01.09  Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ *                      MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ *                      Added definitions and structures for IOC Page 2 and
+ *                      RAID Volume Page 2.
+ *  --------------------------------------------------------------------------
+
+mpi_init.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added MPI_SCSI_RSP_INFO_ definitions.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_targ.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-22-00  01.00.02  Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ *                      Corrected DECSRIPTOR typo to DESCRIPTOR.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Modified target mode to use IoIndex instead of
+ *                      HostIndex and IocIndex. Added Alias.
+ *  01-09-01  01.01.02  Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ *                      and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ *                      MPI_TARGET_FCP_CMD_BUFFER.
+ *  --------------------------------------------------------------------------
+
+mpi_fc.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added _MSG_FC_ABORT_REPLY structure.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added messages for Common Transport Send and
+ *                      Primitive Send.
+ *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *                      and modified the FcPrimitiveSend flags.
+ *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
+ *                      field.
+ *                      Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ *                      FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_lan.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ *                      Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ *                      Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added MPI_ to BUCKETSTATUS_ definitions.
+ *  06-22-00  01.00.03  Major changes to match new LAN definition in 1.0 spec.
+ *  06-30-00  01.00.04  Added Context Reply definitions per revised proposal.
+ *                      Changed transaction context usage to bucket/buffer.
+ *  07-05-00  01.00.05  Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ *                      to lan private header file
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_raid.h
+ *  02-27-01  01.01.01  Original release for this file.
+ *  --------------------------------------------------------------------------
+
+mpi_type.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_history.txt         Parts list history
+
+Filename    01.01.08   01.01.07   01.01.06   01.01.05   01.01.04
+----------  --------   --------   --------   --------   --------
+mpi.h       01.01.06   01.01.05   01.01.04   01.01.04   01.01.03
+mpi_ioc.h   01.01.05   01.01.04   01.01.03   01.01.03   01.01.03
+mpi_cnfg.h  01.01.09   01.01.08   01.01.07   01.01.06   01.01.05
+mpi_init.h  01.01.03   01.01.03   01.01.02   01.01.02   01.01.02
+mpi_targ.h  01.01.03   01.01.03   01.01.02   01.01.02   01.01.02
+mpi_fc.h    01.01.05   01.01.05   01.01.04   01.01.04   01.01.03
+mpi_lan.h   01.01.02   01.01.02   01.01.01   01.01.01   01.01.01
+mpi_raid.h  01.01.01
+mpi_type.h  01.01.02   01.01.02   01.01.01   01.01.01   01.01.01
+
+Filename    01.01.03   01.01.02   01.01.01   01.00.07   01.00.06   01.00.05
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.01.02   01.01.02   01.01.01   01.00.04   01.00.04   01.00.03
+mpi_ioc.h   01.01.02   01.01.02   01.01.01   01.00.05   01.00.04   01.00.03
+mpi_cnfg.h  01.01.04   01.01.03   01.01.01   01.00.05   01.00.05   01.00.04
+mpi_init.h  01.01.02   01.01.02   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_targ.h  01.01.01   01.01.01   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_fc.h    01.01.02   01.01.02   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_lan.h   01.01.01   01.01.01   01.01.01   01.00.05   01.00.05   01.00.05
+mpi_type.h  01.01.01   01.01.01   01.01.01   01.00.01   01.00.01   01.00.01
+
+Filename     01.00.04   01.00.03   01.00.02   01.00.01   00.10.02   00.10.01
+----------   --------   --------   --------   --------   --------   --------
+mpi.h        01.00.02   01.00.01   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_ioc.h    01.00.02   01.00.02   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_cnfg.h   01.00.03   01.00.02   01.00.02   01.00.01   00.10.01   00.10.01
+mpi_init.h   01.00.02   01.00.02   01.00.02   01.00.01   00.10.02   00.10.01
+mpi_targ.h   01.00.02   01.00.01   01.00.01   01.00.01   00.10.01   00.10.01
+mpi_fc.h     01.00.02   01.00.02   01.00.01   01.00.01   00.10.01   00.10.01
+mpi_lan.h    01.00.03   01.00.02   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_type.h   01.00.01   01.00.01   01.00.01   01.00.01   00.10.01   00.10.01
+
+
+ *  --------------------------------------------------------------------------
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_init.h linux/drivers/message/fusion/lsi/mpi_init.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_init.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_init.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,215 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_INIT.H
+ *          Title:  MPI initiator mode messages and structures
+ *  Creation Date:  June 8, 2000
+ *
+ *    MPI Version:  01.01.03
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added MPI_SCSI_RSP_INFO_ definitions.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *  12-04-00  01.01.02  Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_INIT_H
+#define MPI_INIT_H
+
+
+/*****************************************************************************
+*
+*               S C S I    I n i t i a t o r    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  SCSI IO messages and assocaited structures                              */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_REQUEST
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      CDBLength;
+    U8                      SenseBufferLength;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      LUN[8];
+    U32                     Control;
+    U8                      CDB[16];
+    U32                     DataLength;
+    U32                     SenseBufferLowAddr;
+    SGE_IO_UNION            SGL;
+} MSG_SCSI_IO_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_REQUEST,
+  SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t;
+
+
+/* SCSIO MsgFlags bits */
+
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH          (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32       (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64       (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION       (0x02)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST       (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC        (0x02)
+
+/* SCSIIO LUN fields */
+
+#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING   (0x0000FFFF)
+#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING  (0xFFFF0000)
+#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING   (0x0000FFFF)
+#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING  (0xFFFF0000)
+#define MPI_SCSIIO_LUN_LEVEL_1_WORD             (0xFF00)
+#define MPI_SCSIIO_LUN_LEVEL_1_DWORD            (0x0000FF00)
+
+/* SCSIO Control bits */
+
+#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK   (0x03000000)
+#define MPI_SCSIIO_CONTROL_NODATATRANSFER       (0x00000000)
+#define MPI_SCSIIO_CONTROL_WRITE                (0x01000000)
+#define MPI_SCSIIO_CONTROL_READ                 (0x02000000)
+
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK       (0x3C000000)
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT      (26)
+
+#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK   (0x00000700)
+#define MPI_SCSIIO_CONTROL_SIMPLEQ              (0x00000000)
+#define MPI_SCSIIO_CONTROL_HEADOFQ              (0x00000100)
+#define MPI_SCSIIO_CONTROL_ORDEREDQ             (0x00000200)
+#define MPI_SCSIIO_CONTROL_ACAQ                 (0x00000400)
+#define MPI_SCSIIO_CONTROL_UNTAGGED             (0x00000500)
+#define MPI_SCSIIO_CONTROL_NO_DISCONNECT        (0x00000700)
+
+#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK      (0x00FF0000)
+#define MPI_SCSIIO_CONTROL_OBSOLETE             (0x00800000)
+#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV        (0x00400000)
+#define MPI_SCSIIO_CONTROL_TARGET_RESET         (0x00200000)
+#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV        (0x00100000)
+#define MPI_SCSIIO_CONTROL_RESERVED             (0x00080000)
+#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV     (0x00040000)
+#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET       (0x00020000)
+#define MPI_SCSIIO_CONTROL_RESERVED2            (0x00010000)
+
+
+/* SCSIIO reply structure */
+typedef struct _MSG_SCSI_IO_REPLY
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      CDBLength;
+    U8                      SenseBufferLength;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      SCSIStatus;
+    U8                      SCSIState;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     TransferCount;
+    U32                     SenseCount;
+    U32                     ResponseInfo;
+} MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY,
+  SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
+
+
+/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */
+
+#define MPI_SCSI_STATUS_SUCCESS                 (0x00)
+#define MPI_SCSI_STATUS_CHECK_CONDITION         (0x02)
+#define MPI_SCSI_STATUS_CONDITION_MET           (0x04)
+#define MPI_SCSI_STATUS_BUSY                    (0x08)
+#define MPI_SCSI_STATUS_INTERMEDIATE            (0x10)
+#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET    (0x14)
+#define MPI_SCSI_STATUS_RESERVATION_CONFLICT    (0x18)
+#define MPI_SCSI_STATUS_COMMAND_TERMINATED      (0x22)
+#define MPI_SCSI_STATUS_TASK_SET_FULL           (0x28)
+#define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
+
+
+/* SCSIIO Reply SCSIState values */
+
+#define MPI_SCSI_STATE_AUTOSENSE_VALID          (0x01)
+#define MPI_SCSI_STATE_AUTOSENSE_FAILED         (0x02)
+#define MPI_SCSI_STATE_NO_SCSI_STATUS           (0x04)
+#define MPI_SCSI_STATE_TERMINATED               (0x08)
+#define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
+
+/* SCSIIO Reply ResponseInfo values */
+/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
+
+#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE     (0x00000000)
+#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR   (0x01000000)
+#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID   (0x02000000)
+#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR     (0x03000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED      (0x05000000)
+#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE   (0x06000000)
+
+
+/****************************************************************************/
+/*  SCSI Task Management messages                                           */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_TASK_MGMT
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved;
+    U8                      TaskType;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      LUN[8];
+    U32                     Reserved2[7];
+    U32                     TaskMsgContext;
+} MSG_SCSI_TASK_MGMT, MPI_POINTER PTR_SCSI_TASK_MGMT,
+  SCSITaskMgmt_t, MPI_POINTER pSCSITaskMgmt_t;
+
+/* TaskType values */
+
+#define MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK        (0x00000001)
+#define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET     (0x00000002)
+#define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET      (0x00000003)
+#define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS         (0x00000004)
+
+/* MsgFlags bits */
+#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION  (0x00000002)
+
+/* SCSI Task Management Reply */
+typedef struct _MSG_SCSI_TASK_MGMT_REPLY
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved;
+    U8                      TaskType;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     TerminationCount;
+} MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
+  SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_ioc.h linux/drivers/message/fusion/lsi/mpi_ioc.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_ioc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_ioc.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,583 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_IOC.H
+ *          Title:  MPI IOC, Port, Event, FW Load, and ToolBox messages
+ *  Creation Date:  August 11, 2000
+ *
+ *    MPI Version:  01.01.05
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added _MSG_IOC_INIT_REPLY structure.
+ *  06-06-00  01.00.01  Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ *  06-12-00  01.00.02  Added _MSG_PORT_ENABLE_REPLY structure.
+ *                      Added _MSG_EVENT_ACK_REPLY structure.
+ *                      Added _MSG_FW_DOWNLOAD_REPLY structure.
+ *                      Added _MSG_TOOLBOX_REPLY structure.
+ *  06-30-00  01.00.03  Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ *  07-27-00  01.00.04  Added _EVENT_DATA structure definitions for _SCSI,
+ *                      _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ *  08-11-00  01.00.05  Switched positions of MsgLength and Function fields in
+ *                      _MSG_EVENT_ACK_REPLY structure to match specification.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *                      Added a value for Manufacturer to WhoInit.
+ *  12-04-00  01.01.02  Modified IOCFacts reply, added FWUpload messages, and
+ *                      removed toolbox message.
+ *  01-09-01  01.01.03  Added event enabled and disabled defines.
+ *                      Added structures for FwHeader and DataHeader.
+ *                      Added ImageType to FwUpload reply.
+ *  02-20-01  01.01.04  Started using MPI_POINTER.
+ *  02-27-01  01.01.05  Added event for RAID status change and its event data.
+ *                      Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_IOC_H
+#define MPI_IOC_H
+
+
+/*****************************************************************************
+*
+*               I O C    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  IOCInit message                                                         */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_INIT
+{
+    U8                      WhoInit;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Flags;
+    U8                      MaxDevices;
+    U8                      MaxBuses;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     ReplyFrameSize;
+    U8                      Reserved1[2];
+    U32                     HostMfaHighAddr;
+    U32                     SenseBufferHighAddr;
+} MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
+  IOCInit_t, MPI_POINTER pIOCInit_t;
+
+typedef struct _MSG_IOC_INIT_REPLY
+{
+    U8                      WhoInit;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Flags;
+    U8                      MaxDevices;
+    U8                      MaxBuses;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY,
+  IOCInitReply_t, MPI_POINTER pIOCInitReply_t;
+
+/* WhoInit values */
+
+#define MPI_WHOINIT_NO_ONE                      (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS                 (0x01)
+#define MPI_WHOINIT_ROM_BIOS                    (0x02)
+#define MPI_WHOINIT_PCI_PEER                    (0x03)
+#define MPI_WHOINIT_HOST_DRIVER                 (0x04)
+#define MPI_WHOINIT_MANUFACTURER                (0x05)
+
+
+/****************************************************************************/
+/*  IOC Facts message                                                       */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_FACTS
+{
+    U8                      Reserved[2];
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS,
+  IOCFacts_t, MPI_POINTER pIOCFacts_t;
+
+/* IOC Facts Reply */
+
+typedef struct _MSG_IOC_FACTS_REPLY
+{
+    U16                     MsgVersion;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved;
+    U8                      IOCNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U8                      MaxChainDepth;
+    U8                      WhoInit;
+    U8                      BlockSize;
+    U8                      Flags;
+    U16                     ReplyQueueDepth;
+    U16                     RequestFrameSize;
+    U16                     FWVersion;
+    U16                     ProductID;
+    U32                     CurrentHostMfaHighAddr;
+    U16                     GlobalCredits;
+    U8                      NumberOfPorts;
+    U8                      EventState;
+    U32                     CurrentSenseBufferHighAddr;
+    U16                     CurReplyFrameSize;
+    U8                      MaxDevices;
+    U8                      MaxBuses;
+    U32                     FWImageSize;
+    U32                     DataImageSize;
+} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
+  IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
+
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK      (0xFF00)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK      (0x00FF)
+
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT     (0x01)
+#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD    (0x02)
+
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED        (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED         (0x01)
+
+
+
+/*****************************************************************************
+*
+*               P o r t    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Port Facts message and Reply                                            */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_FACTS
+{
+     U8                     Reserved[2];
+     U8                     ChainOffset;
+     U8                     Function;
+     U8                     Reserved1[2];
+     U8                     PortNumber;
+     U8                     MsgFlags;
+     U32                    MsgContext;
+} MSG_PORT_FACTS, MPI_POINTER PTR_MSG_PORT_FACTS,
+  PortFacts_t, MPI_POINTER pPortFacts_t;
+
+typedef struct _MSG_PORT_FACTS_REPLY
+{
+     U16                    Reserved;
+     U8                     MsgLength;
+     U8                     Function;
+     U16                    Reserved1;
+     U8                     PortNumber;
+     U8                     MsgFlags;
+     U32                    MsgContext;
+     U16                    Reserved2;
+     U16                    IOCStatus;
+     U32                    IOCLogInfo;
+     U8                     Reserved3;
+     U8                     PortType;
+     U16                    MaxDevices;
+     U16                    PortSCSIID;
+     U16                    ProtocolFlags;
+     U16                    MaxPostedCmdBuffers;
+     U16                    MaxPersistentIDs;
+     U16                    MaxLanBuckets;
+     U16                    Reserved4;
+     U32                    Reserved5;
+} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY,
+  PortFactsReply_t, MPI_POINTER pPortFactsReply_t;
+
+
+/* PortTypes values */
+
+#define MPI_PORTFACTS_PORTTYPE_INACTIVE         (0x00)
+#define MPI_PORTFACTS_PORTTYPE_SCSI             (0x01)
+#define MPI_PORTFACTS_PORTTYPE_FC               (0x10)
+
+/* ProtocolFlags values */
+
+#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR       (0x01)
+#define MPI_PORTFACTS_PROTOCOL_LAN              (0x02)
+#define MPI_PORTFACTS_PROTOCOL_TARGET           (0x04)
+#define MPI_PORTFACTS_PROTOCOL_INITIATOR        (0x08)
+
+
+/****************************************************************************/
+/*  Port Enable Message                                                     */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_ENABLE
+{
+    U8                      Reserved[2];
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[2];
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_PORT_ENABLE, MPI_POINTER PTR_MSG_PORT_ENABLE,
+  PortEnable_t, MPI_POINTER pPortEnable_t;
+
+typedef struct _MSG_PORT_ENABLE_REPLY
+{
+    U8                      Reserved[2];
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[2];
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_PORT_ENABLE_REPLY, MPI_POINTER PTR_MSG_PORT_ENABLE_REPLY,
+  PortEnableReply_t, MPI_POINTER pPortEnableReply_t;
+
+
+/*****************************************************************************
+*
+*               E v e n t    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Event Notification messages                                             */
+/****************************************************************************/
+
+typedef struct _MSG_EVENT_NOTIFY
+{
+    U8                      Switch;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_EVENT_NOTIFY, MPI_POINTER PTR_MSG_EVENT_NOTIFY,
+  EventNotification_t, MPI_POINTER pEventNotification_t;
+
+/* Event Notification Reply */
+
+typedef struct _MSG_EVENT_NOTIFY_REPLY
+{
+     U16                    EventDataLength;
+     U8                     MsgLength;
+     U8                     Function;
+     U8                     Reserved1[2];
+     U8                     AckRequired;
+     U8                     MsgFlags;
+     U32                    MsgContext;
+     U8                     Reserved2[2];
+     U16                    IOCStatus;
+     U32                    IOCLogInfo;
+     U32                    Event;
+     U32                    EventContext;
+     U32                    Data[1];
+} MSG_EVENT_NOTIFY_REPLY, MPI_POINTER PTR_MSG_EVENT_NOTIFY_REPLY,
+  EventNotificationReply_t, MPI_POINTER pEventNotificationReply_t;
+
+/* Event Acknowledge */
+
+typedef struct _MSG_EVENT_ACK
+{
+    U8                      Reserved[2];
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     Event;
+    U32                     EventContext;
+} MSG_EVENT_ACK, MPI_POINTER PTR_MSG_EVENT_ACK,
+  EventAck_t, MPI_POINTER pEventAck_t;
+
+typedef struct _MSG_EVENT_ACK_REPLY
+{
+    U8                      Reserved[2];
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY,
+  EventAckReply_t, MPI_POINTER pEventAckReply_t;
+
+
+/* Switch */
+
+#define MPI_EVENT_NOTIFICATION_SWITCH_OFF   (0x00)
+#define MPI_EVENT_NOTIFICATION_SWITCH_ON    (0x01)
+
+/* Event */
+
+#define MPI_EVENT_NONE                      (0x00000000)
+#define MPI_EVENT_LOG_DATA                  (0x00000001)
+#define MPI_EVENT_STATE_CHANGE              (0x00000002)
+#define MPI_EVENT_UNIT_ATTENTION            (0x00000003)
+#define MPI_EVENT_IOC_BUS_RESET             (0x00000004)
+#define MPI_EVENT_EXT_BUS_RESET             (0x00000005)
+#define MPI_EVENT_RESCAN                    (0x00000006)
+#define MPI_EVENT_LINK_STATUS_CHANGE        (0x00000007)
+#define MPI_EVENT_LOOP_STATE_CHANGE         (0x00000008)
+#define MPI_EVENT_LOGOUT                    (0x00000009)
+#define MPI_EVENT_EVENT_CHANGE              (0x0000000A)
+#define MPI_EVENT_RAID_STATUS_CHANGE        (0x0000000B)
+
+/* AckRequired field values */
+
+#define MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00)
+#define MPI_EVENT_NOTIFICATION_ACK_REQUIRED     (0x01)
+
+/* SCSI Event data for Port, Bus and Device forms) */
+
+typedef struct _EVENT_DATA_SCSI
+{
+    U8                      TargetID;
+    U8                      BusPort;
+    U16                     Reserved;
+} EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI,
+  EventDataScsi_t, MPI_POINTER pEventDataScsi_t;
+
+/* MPI Link Status Change Event data */
+
+typedef struct _EVENT_DATA_LINK_STATUS
+{
+    U8                      State;
+    U8                      Reserved;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      Port;
+    U16                     Reserved3;
+} EVENT_DATA_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_LINK_STATUS,
+  EventDataLinkStatus_t, MPI_POINTER pEventDataLinkStatus_t;
+
+#define MPI_EVENT_LINK_STATUS_FAILURE       (0x00000000)
+#define MPI_EVENT_LINK_STATUS_ACTIVE        (0x00000001)
+
+/* MPI Loop State Change Event data */
+
+typedef struct _EVENT_DATA_LOOP_STATE
+{
+    U8                      Character4;
+    U8                      Character3;
+    U8                      Type;
+    U8                      Reserved;
+    U8                      Reserved1;
+    U8                      Port;
+    U16                     Reserved2;
+} EVENT_DATA_LOOP_STATE, MPI_POINTER PTR_EVENT_DATA_LOOP_STATE,
+  EventDataLoopState_t, MPI_POINTER pEventDataLoopState_t;
+
+#define MPI_EVENT_LOOP_STATE_CHANGE_LIP     (0x0001)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPE     (0x0002)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPB     (0x0003)
+
+/* MPI LOGOUT Event data */
+
+typedef struct _EVENT_DATA_LOGOUT
+{
+    U32                     NPortID;
+    U8                      Reserved;
+    U8                      Port;
+    U16                     Reserved1;
+} EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
+  EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
+
+/* MPI RAID Status Change Event data */
+
+typedef struct _EVENT_DATA_RAID_STATUS_CHANGE
+{
+    U8                      VolumeTargetID;
+    U8                      VolumeBus;
+    U8                      ReasonCode;
+    U8                      PhysDiskNum;
+    U8                      ASC;
+    U8                      ASCQ;
+    U16                     Reserved;
+} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE,
+  MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t;
+
+
+/* MPI RAID Status Change Event data ReasonCode values */
+
+#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL       (0x00)
+#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED      (0x01)
+#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC       (0x02)
+#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED           (0x03)
+#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING  (0x04)
+#define MPI_EVENT_RAID_DATA_RC_SMART_DATA           (0x05)
+
+
+/*****************************************************************************
+*
+*               F i r m w a r e    L o a d    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Firmware Download message and associated structures                     */
+/****************************************************************************/
+
+typedef struct _MSG_FW_DOWNLOAD
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    SGE_MPI_UNION           SGL;
+} MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD,
+  FWDownload_t, MPI_POINTER pFWDownload_t;
+
+#define MPI_FW_DOWNLOAD_ITYPE_RESERVED      (0x00)
+#define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
+#define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
+
+
+typedef struct _FWDownloadTCSGE
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     Reserved1;
+    U32                     ImageOffset;
+    U32                     ImageSize;
+} FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE,
+  FWDownloadTCSGE_t, MPI_POINTER pFWDownloadTCSGE_t;
+
+/* Firmware Download reply */
+typedef struct _MSG_FW_DOWNLOAD_REPLY
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_FW_DOWNLOAD_REPLY, MPI_POINTER PTR_MSG_FW_DOWNLOAD_REPLY,
+  FWDownloadReply_t, MPI_POINTER pFWDownloadReply_t;
+
+
+/****************************************************************************/
+/*  Firmware Upload message and associated structures                       */
+/****************************************************************************/
+
+typedef struct _MSG_FW_UPLOAD
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    SGE_MPI_UNION           SGL;
+} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD,
+  FWUpload_t, MPI_POINTER pFWUpload_t;
+
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM      (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH        (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH      (0x02)
+#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM    (0x03)
+
+typedef struct _FWUploadTCSGE
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     Reserved1;
+    U32                     ImageOffset;
+    U32                     ImageSize;
+} FW_UPLOAD_TCSGE, MPI_POINTER PTR_FW_UPLOAD_TCSGE,
+  FWUploadTCSGE_t, MPI_POINTER pFWUploadTCSGE_t;
+
+/* Firmware Upload reply */
+typedef struct _MSG_FW_UPLOAD_REPLY
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ActualImageSize;
+} MSG_FW_UPLOAD_REPLY, MPI_POINTER PTR_MSG_FW_UPLOAD_REPLY,
+  FWUploadReply_t, MPI_POINTER pFWUploadReply_t;
+
+
+typedef struct _MPI_FW_HEADER
+{
+    U32                     ArmBranchInstruction0;
+    U32                     Signature0;
+    U32                     Signature1;
+    U32                     Signature2;
+    U32                     ArmBranchInstruction1;
+    U32                     ArmBranchInstruction2;
+    U32                     Reserved;
+    U32                     Checksum;
+    U16                     VendorId;
+    U16                     ProductId;
+    U16                     FwVersion;
+    U16                     Reserved1;
+    U32                     SeqCodeVersion;
+    U32                     ImageSize;
+    U32                     Reserved2;
+    U32                     LoadStartAddress;
+    U32                     IopResetVectorValue;
+    U32                     IopResetRegAddr;
+    U32                     VersionNameWhat;
+    U8                      VersionName[32];
+    U32                     VendorNameWhat;
+    U8                      VendorName[32];
+} MPI_FW_HEADER, MPI_POINTER PTR_MPI_FW_HEADER,
+  MpiFwHeader_t, MPI_POINTER pMpiFwHeader_t;
+
+#define MPI_FW_HEADER_WHAT_SIGNATURE    (0x29232840)
+
+
+typedef struct _MPI_DATA_HEADER
+{
+    U32                     Signature;
+    U16                     FunctionNumber;
+    U16                     Length;
+    U32                     Checksum;
+    U32                     LoadStartAddress;
+} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER,
+  MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t;
+
+#define MPI_DATA_HEADER_SIGNATURE       (0x43504147)
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_lan.h linux/drivers/message/fusion/lsi/mpi_lan.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_lan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_lan.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,204 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_LAN.H
+ *          Title:  MPI LAN messages and structures
+ *  Creation Date:  June 30, 2000
+ *
+ *    MPI Version:  01.01.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ *                      Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ *                      Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added MPI_ to BUCKETSTATUS_ definitions.
+ *  06-22-00  01.00.03  Major changes to match new LAN definition in 1.0 spec.
+ *  06-30-00  01.00.04  Added Context Reply definitions per revised proposal.
+ *                      Changed transaction context usage to bucket/buffer.
+ *  07-05-00  01.00.05  Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ *                      to lan private header file
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_LAN_H
+#define MPI_LAN_H
+
+
+/******************************************************************************
+*
+*               L A N    M e s s a g e s
+*
+*******************************************************************************/
+
+/* LANSend messages */
+
+typedef struct _MSG_LAN_SEND_REQUEST
+{
+    U16                     Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    SGE_MPI_UNION           SG_List[1];
+} MSG_LAN_SEND_REQUEST, MPI_POINTER PTR_MSG_LAN_SEND_REQUEST,
+  LANSendRequest_t, MPI_POINTER pLANSendRequest_t;
+
+
+typedef struct _MSG_LAN_SEND_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved2;
+    U8                      NumberOfContexts;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     BufferContext;
+} MSG_LAN_SEND_REPLY, MPI_POINTER PTR_MSG_LAN_SEND_REPLY,
+  LANSendReply_t, MPI_POINTER pLANSendReply_t;
+
+
+/* LANReceivePost */
+
+typedef struct _MSG_LAN_RECEIVE_POST_REQUEST
+{
+    U16                     Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     BucketCount;
+    SGE_MPI_UNION           SG_List[1];
+} MSG_LAN_RECEIVE_POST_REQUEST, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REQUEST,
+  LANReceivePostRequest_t, MPI_POINTER pLANReceivePostRequest_t;
+
+
+typedef struct _MSG_LAN_RECEIVE_POST_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved2;
+    U8                      NumberOfContexts;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     BucketsRemaining;
+    U32                     PacketOffset;
+    U32                     PacketLength;
+    U32                     BucketContext[1];
+} MSG_LAN_RECEIVE_POST_REPLY, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REPLY,
+  LANReceivePostReply_t, MPI_POINTER pLANReceivePostReply_t;
+
+
+/* LANReset */
+
+typedef struct _MSG_LAN_RESET_REQUEST
+{
+    U16                     Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_LAN_RESET_REQUEST, MPI_POINTER PTR_MSG_LAN_RESET_REQUEST,
+  LANResetRequest_t, MPI_POINTER pLANResetRequest_t;
+
+
+typedef struct _MSG_LAN_RESET_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_LAN_RESET_REPLY, MPI_POINTER PTR_MSG_LAN_RESET_REPLY,
+  LANResetReply_t, MPI_POINTER pLANResetReply_t;
+
+
+/****************************************************************************/
+/* LAN Context Reply defines and macros                                     */
+/****************************************************************************/
+
+#define LAN_REPLY_PACKET_LENGTH_MASK            (0x0000FFFF)
+#define LAN_REPLY_PACKET_LENGTH_SHIFT           (0)
+#define LAN_REPLY_BUCKET_CONTEXT_MASK           (0x07FF0000)
+#define LAN_REPLY_BUCKET_CONTEXT_SHIFT          (16)
+#define LAN_REPLY_BUFFER_CONTEXT_MASK           (0x07FFFFFF)
+#define LAN_REPLY_BUFFER_CONTEXT_SHIFT          (0)
+#define LAN_REPLY_FORM_MASK                     (0x18000000)
+#define LAN_REPLY_FORM_RECEIVE_SINGLE           (0x00)
+#define LAN_REPLY_FORM_RECEIVE_MULTIPLE         (0x01)
+#define LAN_REPLY_FORM_SEND_SINGLE              (0x02)
+#define LAN_REPLY_FORM_MESSAGE_CONTEXT          (0x03)
+#define LAN_REPLY_FORM_SHIFT                    (27)
+
+#define GET_LAN_PACKET_LENGTH(x)    (((x) & LAN_REPLY_PACKET_LENGTH_MASK)   \
+                                        >> LAN_REPLY_PACKET_LENGTH_SHIFT)
+
+#define SET_LAN_PACKET_LENGTH(x, lth)                                       \
+            ((x) = ((x) & ~LAN_REPLY_PACKET_LENGTH_MASK) |                  \
+                            (((lth) << LAN_REPLY_PACKET_LENGTH_SHIFT) &     \
+                                        LAN_REPLY_PACKET_LENGTH_MASK))
+
+#define GET_LAN_BUCKET_CONTEXT(x)   (((x) & LAN_REPLY_BUCKET_CONTEXT_MASK)  \
+                                        >> LAN_REPLY_BUCKET_CONTEXT_SHIFT)
+
+#define SET_LAN_BUCKET_CONTEXT(x, ctx)                                      \
+            ((x) = ((x) & ~LAN_REPLY_BUCKET_CONTEXT_MASK) |                 \
+                            (((ctx) << LAN_REPLY_BUCKET_CONTEXT_SHIFT) &    \
+                                        LAN_REPLY_BUCKET_CONTEXT_MASK))
+
+#define GET_LAN_BUFFER_CONTEXT(x)   (((x) & LAN_REPLY_BUFFER_CONTEXT_MASK)  \
+                                        >> LAN_REPLY_BUFFER_CONTEXT_SHIFT)
+
+#define SET_LAN_BUFFER_CONTEXT(x, ctx)                                      \
+            ((x) = ((x) & ~LAN_REPLY_BUFFER_CONTEXT_MASK) |                 \
+                            (((ctx) << LAN_REPLY_BUFFER_CONTEXT_SHIFT) &    \
+                                        LAN_REPLY_BUFFER_CONTEXT_MASK))
+
+#define GET_LAN_FORM(x)             (((x) & LAN_REPLY_FORM_MASK)            \
+                                        >> LAN_REPLY_FORM_SHIFT)
+
+#define SET_LAN_FORM(x, frm)                                                \
+            ((x) = ((x) & ~LAN_REPLY_FORM_MASK) |                           \
+                            (((frm) << LAN_REPLY_FORM_SHIFT) &              \
+                                        LAN_REPLY_FORM_MASK))
+
+
+/****************************************************************************/
+/* LAN Current Device State defines                                         */
+/****************************************************************************/
+
+#define MPI_LAN_DEVICE_STATE_RESET                     (0x00)
+#define MPI_LAN_DEVICE_STATE_OPERATIONAL               (0x01)
+
+
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_targ.h linux/drivers/message/fusion/lsi/mpi_targ.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_targ.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_targ.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,328 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TARG.H
+ *          Title:  MPI Target mode messages and structures
+ *  Creation Date:  June 22, 2000
+ *
+ *    MPI Version:  01.01.03
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-22-00  01.00.02  Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ *                      Corrected DECSRIPTOR typo to DESCRIPTOR.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Modified target mode to use IoIndex instead of
+ *                      HostIndex and IocIndex. Added Alias.
+ *  01-09-01  01.01.02  Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ *                      and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ *                      MPI_TARGET_FCP_CMD_BUFFER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TARG_H
+#define MPI_TARG_H
+
+
+/******************************************************************************
+*
+*        S C S I    T a r g e t    M e s s a g e s
+*
+*******************************************************************************/
+
+typedef struct _CMD_BUFFER_DESCRIPTOR
+{
+    U16                     IoIndex;
+    U16                     Reserved;
+    union
+    {
+        U32                 PhysicalAddress32;
+        U64                 PhysicalAddress64;
+    } u;
+} CMD_BUFFER_DESCRIPTOR, MPI_POINTER PTR_CMD_BUFFER_DESCRIPTOR,
+  CmdBufferDescriptor_t, MPI_POINTER pCmdBufferDescriptor_t;
+
+
+/****************************************************************************/
+/* Target Command Buffer Post Request                                       */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST
+{
+    U8                      BufferPostFlags;
+    U8                      BufferCount;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      BufferLength;
+    U8                      Reserved;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    CMD_BUFFER_DESCRIPTOR   Buffer[1];
+} MSG_TARGET_CMD_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST,
+  TargetCmdBufferPostRequest_t, MPI_POINTER pTargetCmdBufferPostRequest_t;
+
+#define CMD_BUFFER_POST_FLAGS_PORT_MASK         (0x01)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_MASK    (0x80)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_32      (0)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_64      (1)
+#define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR       (0x80)
+
+#define CMD_BUFFER_POST_IO_INDEX_MASK           (0x00003FFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
+{
+    U8                      BufferPostFlags;
+    U8                      BufferCount;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      BufferLength;
+    U8                      Reserved;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY,
+  TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t;
+
+
+typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      PriorityReason;
+    U8                      Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ReplyWord;
+} MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY,
+  PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t;
+
+#define PRIORITY_REASON_NO_DISCONNECT           (0x00)
+#define PRIORITY_REASON_SCSI_TASK_MANAGEMENT    (0x01)
+#define PRIORITY_REASON_UNKNOWN                 (0xFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ReplyWord;
+} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t;
+
+
+typedef struct _MPI_TARGET_FCP_CMD_BUFFER
+{
+    U8      FcpLun[8];
+    U8      FcpCntl[4];
+    U8      FcpCdb[16];
+    U32     FcpDl;
+} MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
+  MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
+
+
+typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER
+{
+    /* SPI L_Q information unit */
+    U8      L_QType;
+    U8      Reserved;
+    U16     Tag;
+    U8      LogicalUnitNumber[8];
+    U32     DataLength;
+    /* SPI command information unit */
+    U8      ReservedFirstByteOfCommandIU;
+    U8      TaskAttribute;
+    U8      TaskManagementFlags;
+    U8      AdditionalCDBLength;
+    U8      CDB[16];
+} MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+  MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+  MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
+
+
+/****************************************************************************/
+/* Target Assist Request                                                    */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_ASSIST_REQUEST
+{
+    U8                      StatusCode;
+    U8                      TargetAssistFlags;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     QueueTag;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     ReplyWord;
+    U8                      LUN[8];
+    U32                     RelativeOffset;
+    U32                     DataLength;
+    SGE_IO_UNION            SGL[1];
+} MSG_TARGET_ASSIST_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_REQUEST,
+  TargetAssistRequest_t, MPI_POINTER pTargetAssistRequest_t;
+
+#define TARGET_ASSIST_FLAGS_DATA_DIRECTION          (0x01)
+#define TARGET_ASSIST_FLAGS_AUTO_STATUS             (0x02)
+#define TARGET_ASSIST_FLAGS_HIGH_PRIORITY           (0x04)
+#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER       (0x80)
+
+
+typedef struct _MSG_TARGET_ERROR_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ReplyWord;
+    U32                     TransferCount;
+} MSG_TARGET_ERROR_REPLY, MPI_POINTER PTR_MSG_TARGET_ERROR_REPLY,
+  TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t;
+
+
+/****************************************************************************/
+/* Target Status Send Request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_STATUS_SEND_REQUEST
+{
+    U8                      StatusCode;
+    U8                      StatusFlags;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     QueueTag;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     ReplyWord;
+    U8                      LUN[8];
+    SGE_SIMPLE_UNION        StatusDataSGE;
+} MSG_TARGET_STATUS_SEND_REQUEST, MPI_POINTER PTR_MSG_TARGET_STATUS_SEND_REQUEST,
+  TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t;
+
+#define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
+#define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
+
+
+/****************************************************************************/
+/* Target Mode Abort Request                                                */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_MODE_ABORT_REQUEST
+{
+    U8                      AbortType;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     ReplyWord;
+    U32                     MsgContextToAbort;
+} MSG_TARGET_MODE_ABORT, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT,
+  TargetModeAbort_t, MPI_POINTER pTargetModeAbort_t;
+
+#define TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS      (0x00)
+#define TARGET_MODE_ABORT_TYPE_ALL_IO               (0x01)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO             (0x02)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST     (0x03)
+
+/* Target Mode Abort Reply */
+
+typedef struct _MSG_TARGET_MODE_ABORT_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     AbortCount;
+} MSG_TARGET_MODE_ABORT_REPLY, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT_REPLY,
+  TargetModeAbortReply_t, MPI_POINTER pTargetModeAbortReply_t;
+
+
+/****************************************************************************/
+/* Target Mode Context Reply                                                */
+/****************************************************************************/
+
+#define TARGET_MODE_REPLY_IO_INDEX_MASK         (0x00003FFF)
+#define TARGET_MODE_REPLY_IO_INDEX_SHIFT        (0)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK  (0x03FFC000)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14)
+#define TARGET_MODE_REPLY_ALIAS_MASK            (0x0C000000)
+#define TARGET_MODE_REPLY_ALIAS_SHIFT           (26)
+#define TARGET_MODE_REPLY_PORT_MASK             (0x10000000)
+#define TARGET_MODE_REPLY_PORT_SHIFT            (28)
+
+
+#define GET_IO_INDEX(x)     (((x) & TARGET_MODE_REPLY_IO_INDEX_MASK)           \
+                                    >> TARGET_MODE_REPLY_IO_INDEX_SHIFT)
+
+#define SET_IO_INDEX(t, i)                                                     \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_IO_INDEX_MASK) |                  \
+                              (((i) << TARGET_MODE_REPLY_IO_INDEX_SHIFT) &     \
+                                             TARGET_MODE_REPLY_IO_INDEX_MASK))
+
+#define GET_INITIATOR_INDEX(x) (((x) & TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) \
+                                   >> TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT)
+
+#define SET_INITIATOR_INDEX(t, ii)                                             \
+        ((t) = ((t) & ~TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) |               \
+                        (((ii) << TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) &   \
+                                      TARGET_MODE_REPLY_INITIATOR_INDEX_MASK))
+
+#define GET_ALIAS(x) (((x) & TARGET_MODE_REPLY_ALIAS_MASK)                     \
+                                               >> TARGET_MODE_REPLY_ALIAS_SHIFT)
+
+#define SET_ALIAS(t, a)  ((t) = ((t) & ~TARGET_MODE_REPLY_ALIAS_MASK) |        \
+                                    (((a) << TARGET_MODE_REPLY_ALIAS_SHIFT) &  \
+                                                 TARGET_MODE_REPLY_ALIAS_MASK))
+
+#define GET_PORT(x) (((x) & TARGET_MODE_REPLY_PORT_MASK)                       \
+                                               >> TARGET_MODE_REPLY_PORT_SHIFT)
+
+#define SET_PORT(t, p)  ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) |          \
+                                    (((p) << TARGET_MODE_REPLY_PORT_SHIFT) &   \
+                                                  TARGET_MODE_REPLY_PORT_MASK))
+
+
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_type.h linux/drivers/message/fusion/lsi/mpi_type.h
--- v2.4.6/linux/drivers/message/fusion/lsi/mpi_type.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/lsi/mpi_type.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TYPE.H
+ *          Title:  MPI Basic type definitions
+ *  Creation Date:  June 6, 2000
+ *
+ *    MPI Version:  01.01.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TYPE_H
+#define MPI_TYPE_H
+
+
+/*******************************************************************************
+ * Define MPI_POINTER if it hasn't already been defined. By default MPI_POINTER
+ * is defined to be a near pointer. MPI_POINTER can be defined as a far pointer
+ * by defining MPI_POINTER as "far *" before this header file is included.
+ */
+#ifndef MPI_POINTER
+#define MPI_POINTER     *
+#endif
+
+
+/*****************************************************************************
+*
+*               B a s i c    T y p e s
+*
+*****************************************************************************/
+
+typedef signed   char   S8;
+typedef unsigned char   U8;
+typedef signed   short  S16;
+typedef unsigned short  U16;
+
+
+#if defined(unix) || defined(__arm) || defined(ALPHA)
+
+    typedef signed   int   S32;
+    typedef unsigned int   U32;
+
+#else
+
+    typedef signed   long  S32;
+    typedef unsigned long  U32;
+
+#endif
+
+
+typedef struct _S64
+{
+    U32          Low;
+    S32          High;
+} S64;
+
+typedef struct _U64
+{
+    U32          Low;
+    U32          High;
+} U64;
+
+
+/****************************************************************************/
+/*  Pointers                                                                */
+/****************************************************************************/
+
+typedef S8      *PS8;
+typedef U8      *PU8;
+typedef S16     *PS16;
+typedef U16     *PU16;
+typedef S32     *PS32;
+typedef U32     *PU32;
+typedef S64     *PS64;
+typedef U64     *PU64;
+
+
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptbase.c linux/drivers/message/fusion/mptbase.c
--- v2.4.6/linux/drivers/message/fusion/mptbase.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptbase.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,3360 @@
+/*
+ *  linux/drivers/message/fusion/mptbase.c
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      This is the Fusion MPT base driver which supports multiple
+ *      (SCSI + LAN) specialized protocol drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      There are lots of people not mentioned below that deserve credit
+ *      and thanks but won't get it here - sorry in advance that you
+ *      got overlooked.
+ *
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A special thanks to Noah Romer (LSI Logic) for tons of work
+ *      and tough debugging on the LAN driver, especially early on;-)
+ *      And to Roger Hickerson (LSI Logic) for tirelessly supporting
+ *      this driver project.
+ *
+ *      All manner of help from Stephen Shirron (LSI Logic):
+ *      low-level FC analysis, debug + various fixes in FCxx firmware,
+ *      initial port to alpha platform, various driver code optimizations,
+ *      being a faithful sounding board on all sorts of issues & ideas,
+ *      etc.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      Special thanks goes to the I2O LAN driver people at the
+ *      University of Helsinki, who, unbeknownst to them, provided
+ *      the inspiration and initial structure for this driver.
+ *
+ *      A really huge debt of gratitude is owed to Eddie C. Dost
+ *      for gobs of hard work fixing and optimizing LAN code.
+ *      THANK YOU!
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptbase.c,v 1.47 2001/03/22 10:32:23 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME		"Fusion MPT base driver"
+#define my_VERSION	MPT_LINUX_VERSION_COMMON
+#define MYNAM		"mptbase"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*
+ *  cmd line parameters
+ */
+MODULE_PARM(PortIo, "0-1i");
+MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
+MODULE_PARM(HardReset, "0-1i");
+MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset");
+static int PortIo = 0;
+static int HardReset = 1;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public data...
+ */
+int mpt_lan_index = 0;
+int mpt_stm_index = 0;
+
+void *mpt_v_ASCQ_TablePtr = NULL;
+const char **mpt_ScsiOpcodesPtr = NULL;
+int mpt_ASCQ_TableSz = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+					/* Adapter lookup table */
+static MPT_ADAPTER		*mpt_adapters[MPT_MAX_ADAPTERS] = {0};
+static MPT_ADAPTER_TRACKER	 MptAdapters;
+					/* Callback lookup table */
+static MPT_CALLBACK		 MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
+					/* Protocol driver class lookup table */
+static int	 		 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
+					/* Event handler lookup table */
+static MPT_EVHANDLER		 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+
+static int	FusionInitCalled = 0;
+static int	mpt_base_index = -1;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Forward protos...
+ */
+static void	mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
+static int	mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+
+static int 	mpt_adapter_install(struct pci_dev *pdev);
+static void	mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static void	mpt_adapter_disable(MPT_ADAPTER *ioc);
+static void	mpt_adapter_dispose(MPT_ADAPTER *ioc);
+
+static void	MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
+static u32	GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int	GetIocFacts(MPT_ADAPTER *ioc);
+static int	GetPortFacts(MPT_ADAPTER *ioc);
+static int	SendIocInit(MPT_ADAPTER *ioc);
+static int	SendPortEnable(MPT_ADAPTER *ioc, int portnum);
+static int	mpt_fc9x9_reset(MPT_ADAPTER *ioc);
+static int	KickStart(MPT_ADAPTER *ioc);
+static int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
+static int	PrimeIocFifos(MPT_ADAPTER *ioc);
+static int	HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply);
+static int	WaitForDoorbellAck(MPT_ADAPTER *ioc);
+static int	WaitForDoorbellInt(MPT_ADAPTER *ioc);
+static int	WaitForDoorbellReply(MPT_ADAPTER *ioc);
+static int	GetLanConfigPages(MPT_ADAPTER *ioc);
+static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
+
+static int	procmpt_create(void);
+#ifdef CONFIG_PROC_FS
+static int	procmpt_destroy(void);
+#endif
+static int	procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int	procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data);
+/*static int	procmpt_info(char *buf, char **start, off_t offset, int len);*/
+
+static int	ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void	mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
+
+static struct proc_dir_entry	*procmpt_root_dir = NULL;
+
+int		fusion_init(void);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 20000207 -sralston
+ *  GRRRRR...  IOSpace (port i/o) register access (for the 909) is back!
+ * 20000517 -sralston
+ *  Let's trying going back to default mmap register access...
+ */
+
+static inline u32 CHIPREG_READ32(volatile u32 *a)
+{
+	if (PortIo)
+		return inl((unsigned long)a);
+	else
+		return readl(a);
+}
+
+static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v)
+{
+	if (PortIo)
+		outl(v, (unsigned long)a);
+	else
+		writel(v, a);
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
+ *	@irq: irq number (not used)
+ *	@bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ *	@r: pt_regs pointer (not used)
+ *
+ *	This routine is registered via the request_irq() kernel API call,
+ *	and handles all interrupts generated from a specific MPT adapter
+ *	(also referred to as a IO Controller or IOC).
+ *	This routine must clear the interrupt from the adapter and does
+ *	so by reading the reply FIFO.  Multiple replies may be processed
+ *	per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
+ *	which is currently set to 32 in mptbase.h.
+ *
+ *	This routine handles register-level access of the adapter but
+ *	dispatches (calls) a protocol-specific callback routine to handle
+ *	the protocol-specific details of the MPT request completion.
+ */
+static void
+mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
+{
+	MPT_ADAPTER	*ioc;
+	MPT_FRAME_HDR	*mf;
+	MPT_FRAME_HDR	*mr;
+	u32		 pa;
+	u32		*m;
+	int		 req_idx;
+	int		 cb_idx;
+	int		 type;
+	int		 freeme;
+	int		 count = 0;
+
+	ioc = bus_id;
+
+	/*
+	 *  Drain the reply FIFO!
+	 *
+	 * NOTES: I've seen up to 10 replies processed in this loop, so far...
+	 * Update: I've seen up to 9182 replies processed in this loop! ??
+	 * Update: Limit ourselves to processing max of N replies
+	 *	(bottom of loop).
+	 */
+	while (1) {
+
+		if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
+			return;
+
+		cb_idx = 0;
+		freeme = 0;
+
+		/*
+		 *  Check for non-TURBO reply!
+		 */
+		if (pa & MPI_ADDRESS_REPLY_A_BIT) {
+			dma_addr_t reply_dma_addr;
+			u16 ioc_stat;
+
+			/* non-TURBO reply!  Hmmm, something may be up...
+			 *  Newest turbo reply mechanism; get address
+			 *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
+			 */
+			reply_dma_addr = (pa = (pa << 1));
+
+			/* Map DMA address of reply header to cpu address. */
+			m = (u32 *) ((u8 *)ioc->reply_frames +
+					(reply_dma_addr - ioc->reply_frames_dma));
+
+			mr = (MPT_FRAME_HDR *) m;
+			req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
+			cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
+			mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+
+			dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n",
+					ioc->name, mr));
+			DBG_DUMP_REPLY_FRAME(mr)
+
+			/* NEW!  20010301 -sralston
+			 *  Check/log IOC log info
+			 */
+			ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
+	 		if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+				u32	 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+				if ((int)ioc->chip_type <= (int)FC929)
+					mpt_fc_log_info(ioc, log_info);
+				else
+					mpt_sp_log_info(ioc, log_info);
+			}
+		} else {
+			/*
+			 *  Process turbo (context) reply...
+			 */
+			dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa));
+			type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
+			if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
+				cb_idx = mpt_stm_index;
+				mf = NULL;
+				mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+			} else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
+				cb_idx = mpt_lan_index;
+				/*
+				 * BUG FIX!  20001218 -sralston
+				 *  Blind set of mf to NULL here was fatal
+				 *  after lan_reply says "freeme"
+				 *  Fix sort of combined with an optimization here;
+				 *  added explicit check for case where lan_reply
+				 *  was just returning 1 and doing nothing else.
+				 *  For this case skip the callback, but set up
+				 *  proper mf value first here:-)
+				 */
+				if ((pa & 0x58000000) == 0x58000000) {
+					req_idx = pa & 0x0000FFFF;
+					mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+					freeme = 1;
+					/*
+					 *  IMPORTANT!  Invalidate the callback!
+					 */
+					cb_idx = 0;
+				} else {
+					mf = NULL;
+				}
+				mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+			} else {
+				req_idx = pa & 0x0000FFFF;
+				cb_idx = (pa & 0x00FF0000) >> 16;
+				mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+				mr = NULL;
+			}
+			pa = 0;					/* No reply flush! */
+		}
+
+		/*  Check for (valid) IO callback!  */
+		if (cb_idx) {
+			/*  Do the callback!  */
+			freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
+		}
+
+		if (pa) {
+			/*  Flush (non-TURBO) reply with a WRITE!  */
+			CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
+		}
+
+		if (freeme) {
+			unsigned long flags;
+
+			/*  Put Request back on FreeQ!  */
+			spin_lock_irqsave(&ioc->FreeQlock, flags);
+			Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+		}
+
+		count++;
+		dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count));
+		mb();
+
+		if (count >= MPT_MAX_REPLIES_PER_ISR) {
+			dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.",
+					ioc->name, count));
+			dirqprintk((" Giving this ISR a break!\n"));
+			return;
+		}
+
+	}	/* drain reply FIFO */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_base_reply - MPT base driver's callback routine; all base driver
+ *	"internal" request/reply processing is routed here.
+ *	Currently used for EventNotification and EventAck handling.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mf: Pointer to original MPT request frame
+ *	@reply: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *	Returns 1 indicating original alloc'd request frame ptr
+ *	should be freed, or 0 if it shouldn't.
+ */
+static int
+mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+	int freereq = 1;
+	u8 func;
+
+	dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name));
+
+	if ((mf == NULL) ||
+	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+		printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n",
+				ioc->name, mf);
+		return 1;
+	}
+
+	if (reply == NULL) {
+		dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n",
+				ioc->name));
+		return 1;
+	}
+
+	if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+		dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
+		DBG_DUMP_REQUEST_FRAME_HDR(mf)
+	}
+
+	func = reply->u.hdr.Function;
+	dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n",
+			ioc->name, func));
+
+	if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
+		EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
+		int evHandlers = 0;
+		int results;
+
+		results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
+		if (results != evHandlers) {
+			/* CHECKME! Any special handling needed here? */
+			dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n",
+					ioc->name, evHandlers, results));
+		}
+
+		/*
+		 *  Hmmm...  It seems that EventNotificationReply is an exception
+		 *  to the rule of one reply per request.
+		 */
+		if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
+			freereq = 0;
+#ifdef CONFIG_PROC_FS
+//		LogEvent(ioc, pEvReply);
+#endif
+	} else if (func == MPI_FUNCTION_EVENT_ACK) {
+		dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n",
+				ioc->name));
+	} else {
+		printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n",
+				ioc->name, func);
+	}
+
+	/*
+	 *  Conditionally tell caller to free the original
+	 *  EventNotification/EventAck/unexpected request frame!
+	 */
+	return freereq;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_register - Register protocol-specific main callback handler.
+ *	@cbfunc: callback function pointer
+ *	@dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
+ *
+ *	This routine is called by a protocol-specific driver (SCSI host,
+ *	LAN, SCSI target) to register it's reply callback routine.  Each
+ *	protocol-specific driver must do this before it will be able to
+ *	use any IOC resources, such as obtaining request frames.
+ *
+ *	NOTES: The SCSI protocol driver currently calls this routine twice
+ *	in order to register separate callbacks; one for "normal" SCSI IO
+ *	and another for MptScsiTaskMgmt requests.
+ *
+ *	Returns a positive integer valued "handle" in the
+ *	range (and S.O.D. order) {7,6,...,1} if successful.
+ *	Any non-positive return value (including zero!) should be considered
+ *	an error by the caller.
+ */
+int
+mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+{
+	int r = -1;
+	int i;
+
+#ifndef MODULE
+	/*
+	 *  Handle possibility of the mptscsih_detect() routine getting
+	 *  called *before* fusion_init!
+	 */
+	if (!FusionInitCalled) {
+		dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n"));
+		/*
+		 *  NOTE! We'll get recursion here, as fusion_init()
+		 *  calls mpt_register()!
+		 */
+		fusion_init();
+		FusionInitCalled++;
+	}
+#endif
+
+	/*
+	 *  Search for empty callback slot in this order: {7,6,...,1}
+	 *  (slot/handle 0 is reserved!)
+	 */
+	for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+		if (MptCallbacks[i] == NULL) {
+			MptCallbacks[i] = cbfunc;
+			MptDriverClass[i] = dclass;
+			MptEvHandlers[i] = NULL;
+			r = i;
+			if (cbfunc != mpt_base_reply) {
+				MOD_INC_USE_COUNT;
+			}
+			break;
+		}
+	}
+
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_deregister - Deregister a protocol drivers resources.
+ *	@cb_idx: previously registered callback handle
+ *
+ *	Each protocol-specific driver should call this routine when it's
+ *	module is unloaded.
+ */
+void
+mpt_deregister(int cb_idx)
+{
+	if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+		MptCallbacks[cb_idx] = NULL;
+		MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+		MptEvHandlers[cb_idx] = NULL;
+		if (cb_idx != mpt_base_index) {
+			MOD_DEC_USE_COUNT;
+		}
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_event_register - Register protocol-specific event callback
+ *	handler.
+ *	@cb_idx: previously registered (via mpt_register) callback handle
+ *	@ev_cbfunc: callback function
+ *
+ *	This routine can be called by one or more protocol-specific drivers
+ *	if/when they choose to be notified of MPT events.
+ *
+ *	Returns 0 for success.
+ */
+int
+mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+{
+	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+		return -1;
+
+	MptEvHandlers[cb_idx] = ev_cbfunc;
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_event_deregister - Deregister protocol-specific event callback
+ *	handler.
+ *	@cb_idx: previously registered callback handle
+ *
+ *	Each protocol-specific driver should call this routine
+ *	when it does not (or can no longer) handle events,
+ *	or when it's module is unloaded.
+ */
+void
+mpt_event_deregister(int cb_idx)
+{
+	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+		return;
+
+	MptEvHandlers[cb_idx] = NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
+ *	allocated per MPT adapter.
+ *	@handle: Handle of registered MPT protocol driver
+ *	@iocid: IOC unique identifier (integer)
+ *
+ *	Returns pointer to a MPT request frame or %NULL if none are available.
+ */
+MPT_FRAME_HDR*
+mpt_get_msg_frame(int handle, int iocid)
+{
+	MPT_FRAME_HDR *mf = NULL;
+	MPT_ADAPTER *iocp;
+	unsigned long flags;
+
+	/* validate handle and ioc identifier */
+	iocp = mpt_adapters[iocid];
+	spin_lock_irqsave(&iocp->FreeQlock, flags);
+	if (! Q_IS_EMPTY(&iocp->FreeQ)) {
+		int req_offset;
+
+		mf = iocp->FreeQ.head;
+		Q_DEL_ITEM(&mf->u.frame.linkage);
+		mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;	/* byte */
+		req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+								/* u16! */
+		mf->u.frame.hwhdr.msgctxu.fld.req_idx =
+				cpu_to_le16(req_offset / iocp->req_sz);
+		mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+	}
+	spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+	dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
+			iocp->name, handle, iocid, mf));
+	return mf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_put_msg_frame - Send a protocol specific MPT request frame
+ *	to a IOC.
+ *	@handle: Handle of registered MPT protocol driver
+ *	@iocid: IOC unique identifier (integer)
+ *	@mf: Pointer to MPT request frame
+ *
+ *	This routine posts a MPT request frame to the request post FIFO of a
+ *	specific MPT adapter.
+ */
+void
+mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+	MPT_ADAPTER *iocp;
+
+	iocp = mpt_adapters[iocid];
+	if (iocp != NULL) {
+		dma_addr_t mf_dma_addr;
+		int req_offset;
+
+		/* ensure values are reset properly! */
+		mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;		/* byte */
+		req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+									/* u16! */
+		mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz);
+		mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+#ifdef MPT_DEBUG_MSG_FRAME
+		{
+			u32	*m = mf->u.frame.hwhdr.__hdr;
+			int	 i, n;
+
+			printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
+					iocp->name, m);
+			n = iocp->req_sz/4 - 1;
+			while (m[n] == 0)
+				n--;
+			for (i=0; i<=n; i++) {
+				if (i && ((i%8)==0))
+					printk("\n" KERN_INFO " ");
+				printk(" %08x", le32_to_cpu(m[i]));
+			}
+			printk("\n");
+		}
+#endif
+
+		mf_dma_addr = iocp->req_frames_dma + req_offset;
+		CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_free_msg_frame - Place MPT request frame back on FreeQ.
+ *	@handle: Handle of registered MPT protocol driver
+ *	@iocid: IOC unique identifier (integer)
+ *	@mf: Pointer to MPT request frame
+ *
+ *	This routine places a MPT request frame back on the MPT adapter's
+ *	FreeQ.
+ */
+void
+mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+	MPT_ADAPTER *iocp;
+	unsigned long flags;
+
+	iocp = mpt_adapters[iocid];
+	if (iocp != NULL) {
+		/*  Put Request back on FreeQ!  */
+		spin_lock_irqsave(&iocp->FreeQlock, flags);
+		Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+		spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_send_handshake_request - Send MPT request via doorbell
+ *	handshake method.
+ *	@handle: Handle of registered MPT protocol driver
+ *	@iocid: IOC unique identifier (integer)
+ *	@reqBytes: Size of the request in bytes
+ *	@req: Pointer to MPT request frame
+ *
+ *	This routine is used exclusively by mptscsih to send MptScsiTaskMgmt
+ *	requests since they are required to be sent via doorbell handshake.
+ *
+ *	NOTE: It is the callers responsibility to byte-swap fields in the
+ *	request which are greater than 1 byte in size.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+int
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
+{
+	MPT_ADAPTER	*iocp;
+	int		 r = 0;
+
+	iocp = mpt_adapters[iocid];
+	if (iocp != NULL) {
+		u8 *req_as_bytes;
+		int i;
+
+		/*
+		 *  Emulate what mpt_put_msg_frame() does /wrt to sanity
+		 *  setting cb_idx/req_idx.  But ONLY if this request
+		 *  is in proper (pre-alloc'd) request buffer range...
+		 */
+		i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+		if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) {
+			MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
+			mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i);
+			mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+		}
+
+		/*  Make sure there are no doorbells  */
+		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+		CHIPREG_WRITE32(&iocp->chip->Doorbell,
+				((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+				 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+		/*  Wait for IOC doorbell int  */
+		if ((i = WaitForDoorbellInt(iocp)) < 0) {
+			/* FIXME! Recovery action(s)? */
+			/*i = unresponsive_ioc(i);*/
+			return i;
+		}
+
+		dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+				iocp->name, i));
+
+		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+		if ((r = WaitForDoorbellAck(iocp)) < 0)
+			return -2;
+
+		/*  Send request via doorbell handshake  */
+		req_as_bytes = (u8 *) req;
+		for (i = 0; i < reqBytes/4; i++) {
+			u32 word;
+
+			word = ((req_as_bytes[(i*4) + 0] <<  0) |
+				(req_as_bytes[(i*4) + 1] <<  8) |
+				(req_as_bytes[(i*4) + 2] << 16) |
+				(req_as_bytes[(i*4) + 3] << 24));
+			CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
+			if ((r = WaitForDoorbellAck(iocp)) < 0) {
+				r = -3;
+				break;
+			}
+		}
+
+		/*  Make sure there are no doorbells  */
+		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+	}
+
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_adapter_find_first - Find first MPT adapter pointer.
+ *
+ *	Returns first MPT adapter pointer or %NULL if no MPT adapters
+ *	are present.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_first(void)
+{
+	MPT_ADAPTER *this = NULL;
+
+	if (! Q_IS_EMPTY(&MptAdapters))
+		this = MptAdapters.head;
+
+	return this;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * 	mpt_adapter_find_next - Find next MPT adapter pointer.
+ * 	@prev: Pointer to previous MPT adapter
+ *
+ *	Returns next MPT adapter pointer or %NULL if there are no more.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_next(MPT_ADAPTER *prev)
+{
+	MPT_ADAPTER *next = NULL;
+
+	if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
+		next = prev->forw;
+
+	return next;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_pci_scan - Scan PCI devices for MPT adapters.
+ *
+ *	Returns count of MPT adapters found, keying off of PCI vendor and
+ *	device_id's.
+ */
+int __init
+mpt_pci_scan(void)
+{
+	struct pci_dev *pdev;
+	struct pci_dev *pdev2;
+	int found = 0;
+	int count = 0;
+	int r;
+
+	dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
+
+	/*
+	 *  NOTE: The 929 (I believe) will appear as 2 separate PCI devices,
+	 *  one for each channel.
+	 */
+	pci_for_each_dev(pdev) {
+		pdev2 = NULL;
+		if (pdev->vendor != 0x1000)
+			continue;
+
+		if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
+		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+#if 0
+		    /* FIXME! FC919 */
+		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+		    /* FIXME! C103x family */
+		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
+		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
+		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) &&
+#endif
+		    1) {
+			dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device));
+			continue;
+		}
+
+		/* GRRRRR
+		 * 929 dual function devices may be presented in Func 1,0 order,
+		 * but we'd really really rather have them in Func 0,1 order.
+		 * Do some kind of look ahead here...
+		 */
+		if (pdev->devfn & 1) {
+			pdev2 = pci_peek_next_dev(pdev);
+			if (pdev2 && (pdev2->vendor == 0x1000) &&
+			    (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
+			    (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+			    (pdev2->bus->number == pdev->bus->number) &&
+			    !(pdev2->devfn & 1)) {
+				dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+			 		pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
+				found++;
+				if ((r = mpt_adapter_install(pdev2)) == 0)
+					count++;
+			} else {
+				pdev2 = NULL;
+			}
+		}
+
+		dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+			 pdev->bus->number, pdev->devfn, pdev->class, pdev->device));
+		found++;
+		if ((r = mpt_adapter_install(pdev)) == 0)
+			count++;
+
+		if (pdev2)
+			pdev = pdev2;
+	}
+
+	printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n",
+		 found, (found==1) ? "" : "s", count);
+
+	if (count == 0)
+		return -ENODEV;
+
+#ifdef CONFIG_PROC_FS
+	if (procmpt_create() != 0)
+		printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n",
+				MPT_PROCFS_MPTBASEDIR);
+#endif
+
+	return count;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_verify_adapter - Given a unique IOC identifier, set pointer to
+ *	the associated MPT adapter structure.
+ *	@iocid: IOC unique identifier (integer)
+ *	@iocpp: Pointer to pointer to IOC adapter
+ *
+ *	Returns iocid and sets iocpp.
+ */
+int
+mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
+{
+	MPT_ADAPTER *p;
+
+	*iocpp = NULL;
+	if (iocid >= MPT_MAX_ADAPTERS)
+		return -1;
+
+	p = mpt_adapters[iocid];
+	if (p == NULL)
+		return -1;
+
+	*iocpp = p;
+	return iocid;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_adapter_install - Install a PCI intelligent MPT adapter.
+ *	@pdev: Pointer to pci_dev structure
+ *
+ *	This routine performs all the steps necessary to bring the IOC of
+ *	a MPT adapter to a OPERATIONAL state.  This includes registering
+ *	memory regions, registering the interrupt, and allocating request
+ *	and reply memory pools.
+ *
+ *	This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ *	MPT adapter.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ *
+ *	TODO: Add support for polled controllers
+ */
+static int __init
+mpt_adapter_install(struct pci_dev *pdev)
+{
+	MPT_ADAPTER	*ioc;
+	char		*myname;
+	u8		*mem;
+	unsigned long	 mem_phys;
+	unsigned long	 port;
+	u32		 msize;
+	u32		 psize;
+	u32		 ioc_state;
+	int		 i;
+	int		 r = -ENODEV;
+	int 		 cntdn;
+	int		 len;
+	int		 statefault = 0;
+
+	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
+	if (ioc == NULL) {
+		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+		return -ENOMEM;
+	}
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->req_sz = MPT_REQ_SIZE;			/* avoid div by zero! */
+	ioc->alloc_total = sizeof(MPT_ADAPTER);
+
+	ioc->pcidev = pdev;
+
+	/*  Find lookup slot.  GRRRR...  */
+	for (i=0; i < MPT_MAX_ADAPTERS; i++) {
+		if (mpt_adapters[i] == NULL) {
+			ioc->id = i;		/* Assign adapter unique id (lookup) */
+			break;
+		}
+	}
+	if (i == MPT_MAX_ADAPTERS) {
+		printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i);
+		kfree(ioc);
+		return -ENFILE;
+	}
+
+	mem_phys = msize = 0;
+	port = psize = 0;
+	for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+		if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) {
+			/*  Get I/O space!  */
+			port = pdev->PCI_BASEADDR_START(i);
+			psize = PCI_BASEADDR_SIZE(pdev,i);
+		} else {
+			/*  Get memmap  */
+			mem_phys = pdev->PCI_BASEADDR_START(i);
+			msize = PCI_BASEADDR_SIZE(pdev,i);
+			break;
+		}
+	}
+	ioc->mem_size = msize;
+
+	if (i == DEVICE_COUNT_RESOURCE) {
+		printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
+		kfree(ioc);
+		return -EINVAL;
+	}
+
+	dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
+	dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
+	dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap"));
+
+	mem = NULL;
+	if (! PortIo) {
+		/*  Get logical ptr for PciMem0 space  */
+		/*mem = ioremap(mem_phys, msize);*/
+		mem = ioremap(mem_phys, 0x100);
+		if (mem == NULL) {
+			printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+			kfree(ioc);
+			return -EINVAL;
+		}
+		ioc->memmap = mem;
+	}
+	dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+
+	if (PortIo) {
+		u8 *pmem = (u8*)port;
+		ioc->mem_phys = port;
+		ioc->chip = (SYSIF_REGS*)pmem;
+	} else {
+		ioc->mem_phys = mem_phys;
+		ioc->chip = (SYSIF_REGS*)mem;
+	}
+
+	ioc->chip_type = FCUNK;
+	if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
+		ioc->chip_type = FC909;
+		ioc->prod_name = "LSIFC909";
+	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
+		ioc->chip_type = FC929;
+		ioc->prod_name = "LSIFC929";
+	}
+#if 0
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
+		ioc->chip_type = C1030;
+		ioc->prod_name = "LSIFC919";
+	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
+		ioc->chip_type = C1030;
+		ioc->prod_name = "LSI53C1030";
+	}
+#endif
+
+	myname = "iocN";
+	len = strlen(myname);
+	memcpy(ioc->name, myname, len+1);
+	ioc->name[len-1] = '0' + ioc->id;
+
+	Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+	spin_lock_init(&ioc->FreeQlock);
+
+	/*  Disable all!  */
+	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+	ioc->active = 0;
+
+	ioc->pci_irq = -1;
+	if (pdev->irq) {
+		r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
+
+		if (r < 0) {
+			printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n",
+					ioc->name, pdev->irq);
+			iounmap(mem);
+			kfree(ioc);
+			return -EBUSY;
+		}
+
+		ioc->pci_irq = pdev->irq;
+
+		pci_set_master(pdev);			/* ?? */
+
+		dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+	}
+
+	/*  tack onto tail of our MPT adapter list  */
+	Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
+
+	/* Set lookup ptr. */
+	mpt_adapters[ioc->id] = ioc;
+
+	/* NEW!  20010220 -sralston
+	 * Check for "929 bound ports" to reduce redundant resets.
+	 */
+	if (ioc->chip_type == FC929)
+		mpt_detect_929_bound_ports(ioc, pdev);
+
+	/*  Get current [raw] IOC state  */
+	ioc_state = GetIocState(ioc, 0);
+	dhsprintk((KERN_INFO MYNAM ": %s initial [raw] state=%08x\n", ioc->name, ioc_state));
+
+	/*
+	 *  Check to see if IOC got left/stuck in doorbell handshake
+	 *  grip of death.  If so, hard reset the IOC.
+	 */
+	if (ioc_state & MPI_DOORBELL_ACTIVE) {
+		statefault = 1;
+		printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+				ioc->name);
+	}
+
+	/*
+	 *  Check to see if IOC is in FAULT state.
+	 *  If so, hard reset the IOC.
+	 */
+	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+		statefault = 2;
+		printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
+				ioc->name);
+		printk(KERN_WARNING "           FAULT code = %04xh\n",
+				ioc_state & MPI_DOORBELL_DATA_MASK);
+	}
+
+	if (HardReset || statefault) {
+		if ((r = KickStart(ioc)) != 0) {
+			r = -ENODEV;
+			goto ioc_up_fail;
+		}
+	}
+
+	/*
+	 *  Loop here waiting for IOC to come READY.
+	 */
+	i = 0;
+	cntdn = HZ * 10;
+	while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+		if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
+			/*
+			 *  BIOS or previous driver load left IOC in OP state.
+			 *  Reset messaging FIFOs.
+			 */
+			dprintk((KERN_WARNING MYNAM ": %s: Sending IOC msg unit reset!\n", ioc->name));
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
+				printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
+				r = -ENODEV;
+				goto ioc_up_fail;
+			}
+		} else if (ioc_state == MPI_IOC_STATE_RESET) {
+			/*
+			 *  Something is wrong.  Try to get IOC back
+			 *  to a known state.
+			 */
+			dprintk((KERN_WARNING MYNAM ": %s: Sending IO unit reset!\n", ioc->name));
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
+				printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+				r = -ENODEV;
+				goto ioc_up_fail;
+			}
+		}
+
+		i++; cntdn--;
+		if (!cntdn) {
+			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+					ioc->name, (i+5)/HZ);
+			r = -ETIME;
+			goto ioc_up_fail;
+		}
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+
+	if (statefault) {
+		printk(KERN_WARNING MYNAM ": %s: Whew!  Recovered from %s\n",
+				ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT");
+	}
+
+	/*  Enable! (reply interrupt)  */
+	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+	ioc->active = 1;
+
+	/*  Get IOC facts! (first time, ioc->facts0 and ioc->pfacts0)  */
+	if ((r = GetIocFacts(ioc)) != 0)
+		goto ioc_up_fail;
+
+	/* Does IocFacts.EventState need any looking at / attention here? */
+
+	if ((r = SendIocInit(ioc)) != 0)
+		goto ioc_up_fail;
+
+	/*
+	 *  Prime reply & request queues!
+	 *  (mucho alloc's)
+	 */
+	if ((r = PrimeIocFifos(ioc)) != 0)
+		goto ioc_up_fail;
+
+	/*  Get IOC facts again! (2nd time, ioc->factsN and ioc->pfactsN)  */
+	if ((r = GetIocFacts(ioc)) != 0)
+		goto ioc_up_fail;
+
+	/* Does IocFacts.EventState need any looking at / attention here? */
+
+	MptDisplayIocCapabilities(ioc);
+
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+		/*
+		 *  Pre-fetch the ports LAN MAC address!
+		 *  (LANPage1_t stuff)
+		 */
+		(void) GetLanConfigPages(ioc);
+#ifdef MPT_DEBUG
+		{
+			u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+			dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+					ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+		}
+#endif
+	}
+
+	/* NEW!  20010120 -sralston
+	 *  Enable MPT base driver management of EventNotification
+	 *  and EventAck handling.
+	 */
+	(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
+
+	return 0;
+
+ioc_up_fail:
+	//Q_DEL_ITEM(ioc);
+	//mpt_adapter_dispose(ioc);
+	mpt_adapter_disable(ioc);
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_detect_929_bound_ports - Search for PCI bus/dev_function
+ *	which matches PCI bus/dev_function (+/-1) for newly discovered 929.
+ *	@ioc: Pointer to MPT adapter structure
+ *	@pdev: Pointer to (struct pci_dev) structure
+ *
+ *	If match on PCI dev_function +/-1 is found, bind the two MPT adapters
+ *	using alt_ioc pointer fields in their %MPT_ADAPTER structures.
+ */
+static void
+mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+{
+	MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
+	unsigned int match_lo, match_hi;
+
+	match_lo = pdev->devfn-1;
+	match_hi = pdev->devfn+1;
+	dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
+			ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
+
+	while (ioc_srch != NULL) {
+		struct pci_dev *_pcidev = ioc_srch->pcidev;
+
+		if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+		     (_pcidev->bus->number == pdev->bus->number) &&
+		     (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+			/* Paranoia checks */
+			if (ioc->alt_ioc != NULL) {
+				printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+						ioc->name, ioc->alt_ioc->name);
+				break;
+			} else if (ioc_srch->alt_ioc != NULL) {
+				printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+						ioc_srch->name, ioc_srch->alt_ioc->name);
+				break;
+			}
+			dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+					ioc->name, ioc_srch->name));
+			ioc_srch->alt_ioc = ioc;
+			ioc->alt_ioc = ioc_srch;
+			ioc->sod_reset = ioc->alt_ioc->sod_reset;
+			ioc->last_kickstart = ioc->alt_ioc->last_kickstart;
+			break;
+		}
+		ioc_srch = mpt_adapter_find_next(ioc_srch);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_adapter_disable - Disable misbehaving MPT adapter.
+ *	@this: Pointer to MPT adapter structure
+ */
+static void
+mpt_adapter_disable(MPT_ADAPTER *this)
+{
+	if (this != NULL) {
+		int sz;
+
+		/* Disable adapter interrupts! */
+		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+		/* Clear any lingering interrupt */
+		CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+		this->active = 0;
+
+		if (this->reply_alloc != NULL) {
+			sz = (this->reply_sz * this->reply_depth) + 128;
+			pci_free_consistent(this->pcidev, sz,
+					this->reply_alloc, this->reply_alloc_dma);
+			this->reply_frames = NULL;
+			this->reply_alloc = NULL;
+			this->alloc_total -= sz;
+		}
+
+		if (this->req_alloc != NULL) {
+			sz = (this->req_sz * this->req_depth) + 128;
+			/*
+			 *  Rounding UP to nearest 4-kB boundary here...
+			 */
+			sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+			pci_free_consistent(this->pcidev, sz,
+					this->req_alloc, this->req_alloc_dma);
+			this->req_frames = NULL;
+			this->req_alloc = NULL;
+			this->alloc_total -= sz;
+		}
+
+		if (this->sense_buf_pool != NULL) {
+			sz = (this->req_depth * 256);
+			pci_free_consistent(this->pcidev, sz,
+					this->sense_buf_pool, this->sense_buf_pool_dma);
+			this->sense_buf_pool = NULL;
+			this->alloc_total -= sz;
+		}
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_adapter_dispose - Free all resources associated with a MPT
+ *	adapter.
+ *	@this: Pointer to MPT adapter structure
+ *
+ *	This routine unregisters h/w resources and frees all alloc'd memory
+ *	associated with a MPT adapter structure.
+ */
+static void
+mpt_adapter_dispose(MPT_ADAPTER *this)
+{
+	if (this != NULL) {
+		int sz_first, sz_last;
+
+		sz_first = this->alloc_total;
+
+		mpt_adapter_disable(this);
+
+		if (this->pci_irq != -1) {
+			free_irq(this->pci_irq, this);
+			this->pci_irq = -1;
+		}
+
+		if (this->memmap != NULL)
+			iounmap((u8 *) this->memmap);
+
+#if defined(CONFIG_MTRR) && 0
+		if (this->mtrr_reg > 0) {
+			mtrr_del(this->mtrr_reg, 0, 0);
+			dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name));
+		}
+#endif
+
+		/*  Zap the adapter lookup ptr!  */
+		mpt_adapters[this->id] = NULL;
+
+		sz_last = this->alloc_total;
+		dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+				this->name, sz_first-sz_last+(int)sizeof(*this), sz_first));
+		kfree(this);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	MptDisplayIocCapabilities - Disply IOC's capacilities.
+ *	@ioc: Pointer to MPT adapter structure
+ */
+static void
+MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
+{
+	int i = 0;
+
+	printk(KERN_INFO "%s: ", ioc->name);
+	if (ioc->prod_name && strlen(ioc->prod_name) > 3)
+		printk("%s: ", ioc->prod_name+3);
+	printk("Capabilities={");
+
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
+		printk("Initiator");
+		i++;
+	}
+
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+		printk("%sTarget", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+		printk("%sLAN", i ? "," : "");
+		i++;
+	}
+
+#if 0
+	/*
+	 *  This would probably evoke more questions than it's worth
+	 */
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+		printk("%sLogBusAddr", i ? "," : "");
+		i++;
+	}
+#endif
+
+	printk("}\n");
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetIocState - Get the current state of a MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@cooked: Request raw or cooked IOC state
+ *
+ *	Returns all IOC Doorbell register bits if cooked==0, else just the
+ *	Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+static u32
+GetIocState(MPT_ADAPTER *ioc, int cooked)
+{
+	u32 s, sc;
+
+	/*  Get!  */
+	s = CHIPREG_READ32(&ioc->chip->Doorbell);
+	dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s));
+	sc = s & MPI_IOC_STATE_MASK;
+
+	/*  Save!  */
+	ioc->last_state = sc;
+
+	return cooked ? sc : s;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetIocFacts - Send IOCFacts request to MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+GetIocFacts(MPT_ADAPTER *ioc)
+{
+	IOCFacts_t		 get_facts;
+	IOCFactsReply_t		*facts;
+	int			 r;
+	int			 req_sz;
+	int			 reply_sz;
+	u32			 status;
+
+	/*  IOC *must* NOT be in RESET state!  */
+	if (ioc->last_state == MPI_IOC_STATE_RESET) {
+		printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+				ioc->name,
+				ioc->last_state );
+		return -44;
+	}
+
+	facts = &ioc->facts0;
+	/*  Nth (2,3,...) time thru? (been here, done that?)  */
+	if (ioc->facts0.Function == MPI_FUNCTION_IOC_FACTS) {
+		facts = &ioc->factsN;
+	}
+
+	/*  Destination (reply area)...  */
+	reply_sz = sizeof(*facts);
+	memset(facts, 0, reply_sz);
+
+	/*  Request area (get_facts on the stack right now!)  */
+	req_sz = sizeof(get_facts);
+	memset(&get_facts, 0, req_sz);
+
+	get_facts.Function = MPI_FUNCTION_IOC_FACTS;
+	/*  Assert: All other get_facts fields are zero!  */
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending IocFacts%s request\n",
+			ioc->name, facts == &ioc->facts0 ? "0" : "N" ));
+
+	/* No non-zero fields in the get_facts request are greater than
+	 * 1 byte in size, so we can just fire it off as is.
+	 */
+	r = HandShakeReqAndReply(ioc,
+			req_sz, (u32*)&get_facts,
+			reply_sz, (u16*)facts);
+	if (r != 0)
+		return r;
+
+	/*
+	 *  Now byte swap the necessary fields before any further
+	 *  inspection of reply contents.
+	 *
+	 *  But need to do some sanity checks on MsgLength (byte) field
+	 *  to make sure we don't zero IOC's req_sz!
+	 */
+	/* Did we get a valid reply? */
+	if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
+		facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
+		facts->MsgContext = le32_to_cpu(facts->MsgContext);
+		facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
+		facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
+		status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
+		/* CHECKME! IOCStatus, IOCLogInfo */
+
+		facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
+		facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
+		facts->FWVersion = le16_to_cpu(facts->FWVersion);
+		facts->ProductID = le16_to_cpu(facts->ProductID);
+		facts->CurrentHostMfaHighAddr =
+				le32_to_cpu(facts->CurrentHostMfaHighAddr);
+		facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
+		facts->CurrentSenseBufferHighAddr =
+				le32_to_cpu(facts->CurrentSenseBufferHighAddr);
+		facts->CurReplyFrameSize =
+				le16_to_cpu(facts->CurReplyFrameSize);
+
+		/*
+		 *  Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
+		 *  Older MPI-1.00.xx struct had 13 dwords, and enlarged
+		 *  to 14 in MPI-1.01.0x.
+		 */
+		if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) {
+			facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
+			facts->DataImageSize = le32_to_cpu(facts->DataImageSize);
+		}
+
+		if (facts->RequestFrameSize) {
+			/*
+			 *  Set values for this IOC's REQUEST queue size & depth...
+			 */
+			ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4);
+
+			/*
+			 *  Set values for this IOC's REPLY queue size & depth...
+			 *
+			 * BUG? FIX?  20000516 -nromer & sralston 
+			 *  GRRR...  The following did not translate well from MPI v0.09:
+			 *	ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4);
+			 *  to 0.10:
+			 *	ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4);
+			 *  Was trying to minimally optimize to smallest possible reply size
+			 *  (and greatly reduce kmalloc size).  But LAN may need larger reply?
+			 *
+			 *  So for now, just set reply size to request size.  FIXME?
+			 */
+			ioc->reply_sz = ioc->req_sz;
+		} else {
+			/*  Something is wrong!  */
+			printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n",
+					ioc->name);
+			ioc->req_sz = MPT_REQ_SIZE;
+			ioc->reply_sz = MPT_REPLY_SIZE;
+			return -55;
+		}
+		ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits);
+		ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+		dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n",
+				ioc->name, ioc->reply_sz, ioc->reply_depth));
+		dprintk((KERN_INFO MYNAM ": %s: req_sz  =%3d, req_depth  =%4d\n",
+				ioc->name, ioc->req_sz, ioc->req_depth));
+
+		/*  Get port facts!  */
+		if ( (r = GetPortFacts(ioc)) != 0 )
+			return r;
+	} else {
+		printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
+				ioc->name);
+		return -66;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetPortFacts - Send PortFacts request to MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+GetPortFacts(MPT_ADAPTER *ioc)
+{
+	PortFacts_t		 get_pfacts;
+	PortFactsReply_t	*pfacts;
+	int			 i;
+	int			 req_sz;
+	int			 reply_sz;
+
+	/*  IOC *must* NOT be in RESET state!  */
+	if (ioc->last_state == MPI_IOC_STATE_RESET) {
+		printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
+				ioc->name,
+				ioc->last_state );
+		return -4;
+	}
+
+	pfacts = &ioc->pfacts0;
+	/*  Nth (2,3,...) time thru? (been here, done that?)  */
+	if (ioc->pfacts0.Function == MPI_FUNCTION_PORT_FACTS) {
+		pfacts = &ioc->pfactsN;
+	}
+
+	/*  Destination (reply area)...  */
+	reply_sz = sizeof(*pfacts);
+	memset(pfacts, 0, reply_sz);
+
+	/*  Request area (get_pfacts on the stack right now!)  */
+	req_sz = sizeof(get_pfacts);
+	memset(&get_pfacts, 0, req_sz);
+
+	get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
+	/*  Assert: All other get_pfacts fields are zero!  */
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending PortFacts%s request\n",
+			ioc->name, pfacts == &ioc->pfacts0 ? "0" : "N" ));
+
+	/* No non-zero fields in the get_pfacts request are greater than
+	 * 1 byte in size, so we can just fire it off as is.
+	 */
+	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts,
+				reply_sz, (u16*)pfacts);
+	if (i != 0)
+		return i;
+
+	/* Did we get a valid reply? */
+
+	/* Now byte swap the necessary fields in the response. */
+	pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
+	pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
+	pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
+	pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
+	pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
+	pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
+	pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
+	pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
+	pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	SendIocInit - Send IOCInit request to MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocInit(MPT_ADAPTER *ioc)
+{
+	IOCInit_t		 ioc_init;
+	MPIDefaultReply_t	 init_reply;
+	u32			 state;
+	int			 r;
+	int			 count;
+	int			 cntdn;
+
+	memset(&ioc_init, 0, sizeof(ioc_init));
+	memset(&init_reply, 0, sizeof(init_reply));
+
+	ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
+/*	ioc_init.ChainOffset = 0;			*/
+	ioc_init.Function = MPI_FUNCTION_IOC_INIT;
+/*	ioc_init.Flags = 0;				*/
+
+	/*ioc_init.MaxDevices = 16;*/
+	ioc_init.MaxDevices = 255;
+/*	ioc_init.MaxBuses = 16;				*/
+	ioc_init.MaxBuses = 1;
+
+/*	ioc_init.MsgFlags = 0;				*/
+/*	ioc_init.MsgContext = cpu_to_le32(0x00000000);	*/
+	ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);	/* in BYTES */
+	ioc_init.HostMfaHighAddr = cpu_to_le32(0);	/* Say we 32-bit! for now */
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init));
+
+	r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+			sizeof(MPIDefaultReply_t), (u16*)&init_reply);
+	if (r != 0)
+		return r;
+
+	/* No need to byte swap the multibyte fields in the reply
+	 * since we don't even look at it's contents.
+	 */
+
+	if ((r = SendPortEnable(ioc, 0)) != 0)
+		return r;
+
+	/* YIKES!  SUPER IMPORTANT!!!
+	 *  Poll IocState until _OPERATIONAL while IOC is doing
+	 *  LoopInit and TargetDiscovery!
+	 */
+	count = 0;
+	cntdn = HZ * 60;					/* chg'd from 30 to 60 seconds */
+	state = GetIocState(ioc, 1);
+	while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+
+		if (!cntdn) {
+			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n",
+					ioc->name, (count+5)/HZ);
+			return -9;
+		}
+
+		state = GetIocState(ioc, 1);
+		count++;
+	}
+	dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+			ioc->name, count));
+
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	SendPortEnable - Send PortEnable request to MPT adapter port.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@portnum: Port number to enable
+ *
+ *	Send PortEnable to bring IOC to OPERATIONAL state.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+SendPortEnable(MPT_ADAPTER *ioc, int portnum)
+{
+	PortEnable_t		 port_enable;
+	MPIDefaultReply_t	 reply_buf;
+	int	 i;
+	int	 req_sz;
+	int	 reply_sz;
+
+	/*  Destination...  */
+	reply_sz = sizeof(MPIDefaultReply_t);
+	memset(&reply_buf, 0, reply_sz);
+
+	req_sz = sizeof(PortEnable_t);
+	memset(&port_enable, 0, req_sz);
+
+	port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
+	port_enable.PortNumber = portnum;
+/*	port_enable.ChainOffset = 0;		*/
+/*	port_enable.MsgFlags = 0;		*/
+/*	port_enable.MsgContext = 0;		*/
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n",
+			ioc->name, portnum, &port_enable));
+
+	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable,
+			reply_sz, (u16*)&reply_buf);
+	if (i != 0)
+		return i;
+
+	/* We do not even look at the reply, so we need not
+	 * swap the multi-byte fields.
+	 */
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	KickStart - Perform hard reset of MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	This routine places MPT adapter in diagnostic mode via the
+ *	WriteSequence register, and then performs a hard reset of adapter
+ *	via the Diagnostic register.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+KickStart(MPT_ADAPTER *ioc)
+{
+	int r;
+	u32 ioc_state;
+	int cnt = 0;
+
+	dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+
+	if (ioc->chip_type == FC909) {
+		r = mpt_fc9x9_reset(ioc);
+	} else if (ioc->chip_type == FC929) {
+		unsigned long delta;
+
+		delta = jiffies - ioc->last_kickstart;
+		dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n",
+				ioc->name, ioc->last_kickstart, delta));
+		if ((ioc->sod_reset == 0) || (delta >= 10*HZ))
+			r = mpt_fc9x9_reset(ioc);
+		else {
+			dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
+					ioc->name, delta));
+			return 0;
+		}
+	/* TODO! Add FC919!
+	} else if (ioc->chip_type == FC919) {
+	 */
+	/* TODO! Add C1030!
+	} else if (ioc->chip_type == C1030) {
+	 */
+	} else {
+		printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n",
+				ioc->name, ioc->chip_type);
+		return -5;
+	}
+
+	if (r != 0)
+		return -r;
+
+	dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
+			ioc->name));
+
+	for (cnt=0; cnt<HZ*20; cnt++) {
+		if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+			dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n",
+					ioc->name, cnt));
+			return 0;
+		}
+		/* udelay(10000) ? */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+
+	printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n",
+			ioc->name);
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	This routine places FC9x9 adapter in diagnostic mode via the
+ *	WriteSequence register, and then performs a hard reset of adapter
+ *	via the Diagnostic register.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+mpt_fc9x9_reset(MPT_ADAPTER *ioc)
+{
+	u32 diagval;
+
+	/* Use "Diagnostic reset" method! (only thing available!) */
+
+	/*
+	 * Extra read to handle 909 B.0 chip problem with reset
+	 * logic not finishing the RAM access before hard reset hits.
+	 * (? comment taken from NT SYMMPI source)
+	 */
+	(void) CHIPREG_READ32(&ioc->chip->Fubar);
+
+	/*
+	 * Write magic sequence to WriteSequence register.
+	 * But, send 0x0F first to insure a reset to the beginning of the sequence.
+	 */
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_KEY_VALUE_MASK);
+
+	/* Now write magic sequence */
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+	dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence\n",
+			ioc->name));
+
+	/* Now hit the reset bit in the Diagnostic register */
+	CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+
+	udelay(100);
+
+	if ((diagval = CHIPREG_READ32(&ioc->chip->Diagnostic)) &
+				(MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM)) {
+		printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED!\n",
+				ioc->name);
+		return -9;
+	}
+
+	/* TODO!
+	 * Cleanup all event stuff for this IOC;
+	 * re-issue EventNotification request if needed.
+	 */
+	if (ioc->factsN.Function)
+		ioc->factsN.EventState = 0;
+
+	/* NEW!  20010220 -sralston
+	 * Try to avoid redundant resets of the 929.
+	 */
+	ioc->sod_reset++;
+	ioc->last_kickstart = jiffies;
+	if (ioc->alt_ioc) {
+		ioc->alt_ioc->sod_reset = ioc->sod_reset;
+		ioc->alt_ioc->last_kickstart = ioc->last_kickstart;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	SendIocReset - Send IOCReset request to MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@reset_type: reset type, expected values are
+ *	%MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
+ *
+ *	Send IOCReset request to the MPT adapter.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
+{
+	int r;
+
+	printk(KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+			ioc->name, reset_type);
+	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
+	if ((r = WaitForDoorbellAck(ioc)) < 0)
+		return r;
+
+	/* TODO!
+	 *  Cleanup all event stuff for this IOC; re-issue EventNotification
+	 *  request if needed.
+	 */
+	if (ioc->factsN.Function)
+		ioc->factsN.EventState = 0;
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	PrimeIocFifos - Initialize IOC request and reply FIFOs.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	This routine allocates memory for the MPT reply and request frame
+ *	pools, and primes the IOC reply FIFO with reply frames.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+PrimeIocFifos(MPT_ADAPTER *ioc)
+{
+	MPT_FRAME_HDR *mf;
+	unsigned long b;
+	dma_addr_t aligned_mem_dma;
+	u8 *mem, *aligned_mem;
+	int i, sz;
+
+	/*  Prime reply FIFO...  */
+
+	if (ioc->reply_frames == NULL) {
+		sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+		mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma);
+		if (mem == NULL)
+			goto out_fail;
+
+		memset(mem, 0, sz);
+		ioc->alloc_total += sz;
+		ioc->reply_alloc = mem;
+		dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%08x], sz=%d bytes\n",
+			 ioc->name, mem, ioc->reply_alloc_dma, sz));
+
+		b = (unsigned long) mem;
+		b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+		aligned_mem = (u8 *) b;
+		ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
+		ioc->reply_frames_dma =
+			(ioc->reply_alloc_dma + (aligned_mem - mem));
+		aligned_mem_dma = ioc->reply_frames_dma;
+		dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n",
+			 ioc->name, aligned_mem, aligned_mem_dma));
+
+		for (i = 0; i < ioc->reply_depth; i++) {
+			/*  Write each address to the IOC!  */
+			CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
+			aligned_mem_dma += ioc->reply_sz;
+		}
+	}
+
+
+	/*  Request FIFO - WE manage this!  */
+
+	if (ioc->req_frames == NULL) {
+		sz = (ioc->req_sz * ioc->req_depth) + 128;
+		/*
+		 *  Rounding UP to nearest 4-kB boundary here...
+		 */
+		sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+
+		mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma);
+		if (mem == NULL)
+			goto out_fail;
+
+		memset(mem, 0, sz);
+		ioc->alloc_total += sz;
+		ioc->req_alloc = mem;
+		dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%08x], sz=%d bytes\n",
+			 ioc->name, mem, ioc->req_alloc_dma, sz));
+
+		b = (unsigned long) mem;
+		b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+		aligned_mem = (u8 *) b;
+		ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
+		ioc->req_frames_dma =
+			(ioc->req_alloc_dma + (aligned_mem - mem));
+		aligned_mem_dma = ioc->req_frames_dma;
+
+		dprintk((KERN_INFO MYNAM ": %s.req_frames   @ %p[%08x]\n",
+			 ioc->name, aligned_mem, aligned_mem_dma));
+
+		for (i = 0; i < ioc->req_depth; i++) {
+			mf = (MPT_FRAME_HDR *) aligned_mem;
+
+			/*  Queue REQUESTs *internally*!  */
+			Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
+			aligned_mem += ioc->req_sz;
+		}
+
+#if defined(CONFIG_MTRR) && 0
+		/*
+		 *  Enable Write Combining MTRR for IOC's memory region.
+		 *  (at least as much as we can; "size and base must be
+		 *  multiples of 4 kiB"
+		 */
+		ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
+					 sz,
+					 MTRR_TYPE_WRCOMB, 1);
+		dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n",
+				ioc->name, ioc->req_alloc_dma,
+				sz ));
+#endif
+
+	}
+
+	if (ioc->sense_buf_pool == NULL) {
+		sz = (ioc->req_depth * 256);
+		ioc->sense_buf_pool =
+				pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
+		if (ioc->sense_buf_pool == NULL)
+			goto out_fail;
+
+		ioc->alloc_total += sz;
+	}
+
+	return 0;
+
+out_fail:
+	if (ioc->reply_alloc != NULL) {
+		sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+		pci_free_consistent(ioc->pcidev,
+				sz,
+				ioc->reply_alloc, ioc->reply_alloc_dma);
+		ioc->reply_frames = NULL;
+		ioc->reply_alloc = NULL;
+		ioc->alloc_total -= sz;
+	}
+	if (ioc->req_alloc != NULL) {
+		sz = (ioc->req_sz * ioc->req_depth) + 128;
+		/*
+		 *  Rounding UP to nearest 4-kB boundary here...
+		 */
+		sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+		pci_free_consistent(ioc->pcidev,
+				sz,
+				ioc->req_alloc, ioc->req_alloc_dma);
+#if defined(CONFIG_MTRR) && 0
+		if (ioc->mtrr_reg > 0) {
+			mtrr_del(ioc->mtrr_reg, 0, 0);
+			dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n",
+					ioc->name));
+		}
+#endif
+		ioc->req_frames = NULL;
+		ioc->req_alloc = NULL;
+		ioc->alloc_total -= sz;
+	}
+	if (ioc->sense_buf_pool != NULL) {
+		sz = (ioc->req_depth * 256);
+		pci_free_consistent(ioc->pcidev,
+				sz,
+				ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
+		ioc->sense_buf_pool = NULL;
+	}
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	HandShakeReqAndReply - Send MPT request to and receive reply from
+ *	IOC via doorbell handshake method.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@reqBytes: Size of the request in bytes
+ *	@req: Pointer to MPT request frame
+ *	@replyBytes: Expected size of the reply in bytes
+ *	@u16reply: Pointer to area where reply should be written
+ *
+ *	NOTES: It is the callers responsibility to byte-swap fields in the
+ *	request which are greater than 1 byte in size.  It is also the
+ *	callers responsibility to byte-swap response fields which are
+ *	greater than 1 byte in size.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply)
+{
+	MPIDefaultReply_t *mptReply;
+	int failcnt = 0;
+	int t;
+
+	/*
+	 * Get ready to cache a handshake reply
+	 */
+	ioc->hs_reply_idx = 0;
+	mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+	mptReply->MsgLength = 0;
+
+	/*
+	 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
+	 * then tell IOC that we want to handshake a request of N words.
+	 * (WRITE u32val to Doorbell reg).
+	 */
+	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+	CHIPREG_WRITE32(&ioc->chip->Doorbell,
+			((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+			 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+	/*
+	 * Wait for IOC's doorbell handshake int
+	 */
+	if ((t = WaitForDoorbellInt(ioc)) < 0)
+		failcnt++;
+
+	dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
+			ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+	/*
+	 * Clear doorbell int (WRITE 0 to IntStatus reg),
+	 * then wait for IOC to ACKnowledge that it's ready for
+	 * our handshake request.
+	 */
+	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+	if (!failcnt && (t = WaitForDoorbellAck(ioc)) < 0)
+		failcnt++;
+
+	if (!failcnt) {
+		int	 i;
+		u8	*req_as_bytes = (u8 *) req;
+
+		/*
+		 * Stuff request words via doorbell handshake,
+		 * with ACK from IOC for each.
+		 */
+		for (i = 0; !failcnt && i < reqBytes/4; i++) {
+			u32 word = ((req_as_bytes[(i*4) + 0] <<  0) |
+				    (req_as_bytes[(i*4) + 1] <<  8) |
+				    (req_as_bytes[(i*4) + 2] << 16) |
+				    (req_as_bytes[(i*4) + 3] << 24));
+
+			CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
+			if ((t = WaitForDoorbellAck(ioc)) < 0)
+				failcnt++;
+		}
+
+		dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
+		DBG_DUMP_REQUEST_FRAME_HDR(req)
+
+		dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n",
+				ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
+
+		/*
+		 * Wait for completion of doorbell handshake reply from the IOC
+		 */
+		if (!failcnt && (t = WaitForDoorbellReply(ioc)) < 0)
+			failcnt++;
+
+		/*
+		 * Copy out the cached reply...
+		 */
+		for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++)
+			u16reply[i] = ioc->hs_reply[i];
+	} else {
+		return -99;
+	}
+
+	return -failcnt;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
+ *	in it's IntStatus register.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	This routine waits (up to ~30 seconds max) for IOC doorbell
+ *	handshake ACKnowledge.
+ *
+ *	Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellAck(MPT_ADAPTER *ioc)
+{
+	int cntdn = HZ * 30;			/* ~30 seconds */
+	int count = 0;
+	u32 intstat;
+
+	while (--cntdn) {
+		intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+		if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+			break;
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+		count++;
+	}
+
+	if (cntdn) {
+		dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n",
+				ioc->name, count));
+		return count;
+	}
+
+	printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n",
+			ioc->name, (count+5)/HZ);
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
+ *	in it's IntStatus register.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	This routine waits (up to ~30 seconds max) for IOC doorbell interrupt.
+ *
+ *	Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellInt(MPT_ADAPTER *ioc)
+{
+	int cntdn = HZ * 30;			/* ~30 seconds */
+	int count = 0;
+	u32 intstat;
+
+	while (--cntdn) {
+		intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+		if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+			break;
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+		count++;
+	}
+
+	if (cntdn) {
+		dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n",
+				ioc->name, count));
+		return count;
+	}
+
+	printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n",
+			ioc->name, (count+5)/HZ);
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	This routine polls the IOC for a handshake reply, 16 bits at a time.
+ *	Reply is cached to IOC private area large enough to hold a maximum
+ *	of 128 bytes of reply data.
+ *
+ *	Returns a negative value on failure, else size of reply in WORDS.
+ */
+static int
+WaitForDoorbellReply(MPT_ADAPTER *ioc)
+{
+	int u16cnt = 0;
+	int failcnt = 0;
+	int t;
+	u16 *hs_reply = ioc->hs_reply;
+ 	volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+	u16 hword;
+
+	hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
+
+	/*
+	 * Get first two u16's so we can look at IOC's intended reply MsgLength
+	 */
+	for (u16cnt=0; !failcnt && u16cnt < 2; u16cnt++) {
+		if ((t = WaitForDoorbellInt(ioc)) < 0)
+			failcnt++;
+		hs_reply[u16cnt] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+	}
+
+	dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
+			ioc->name, le32_to_cpu(*(u32 *)hs_reply),
+			failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+	/*
+	 * If no error (and IOC said MsgLength is > 0), piece together
+	 * reply 16 bits at a time.
+	 */
+	for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
+		if ((t = WaitForDoorbellInt(ioc)) < 0)
+			failcnt++;
+		hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+		/* don't overflow our IOC hs_reply[] buffer! */
+		if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
+			hs_reply[u16cnt] = hword;
+		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+	}
+
+	if (!failcnt && (t = WaitForDoorbellInt(ioc)) < 0)
+		failcnt++;
+	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+	if (failcnt) {
+		printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n",
+				ioc->name);
+		return -failcnt;
+	}
+#if 0
+	else if (u16cnt != (2 * mptReply->MsgLength)) {
+		return -101;
+	}
+	else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
+		return -102;
+	}
+#endif
+
+	dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name));
+	DBG_DUMP_REPLY_FRAME(mptReply)
+
+	dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n",
+			ioc->name, u16cnt/2));
+	return u16cnt/2;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetLanConfigPages - Fetch LANConfig pages.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+	Config_t		 config_req;
+	ConfigReply_t		 config_reply;
+	LANPage0_t		*page0;
+	dma_addr_t		 page0_dma;
+	LANPage1_t		*page1;
+	dma_addr_t		 page1_dma;
+	int			 i;
+	int			 req_sz;
+	int			 reply_sz;
+	int			 data_sz;
+
+/* LANPage0 */
+	/*  Immediate destination (reply area)...  */
+	reply_sz = sizeof(config_reply);
+	memset(&config_reply, 0, reply_sz);
+
+	/*  Ultimate destination...  */
+	page0 = &ioc->lan_cnfg_page0;
+	data_sz = sizeof(*page0);
+	memset(page0, 0, data_sz);
+
+	/*  Request area (config_req on the stack right now!)  */
+	req_sz = sizeof(config_req);
+	memset(&config_req, 0, req_sz);
+	config_req.Function = MPI_FUNCTION_CONFIG;
+	config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	/*	config_req.Header.PageVersion = 0;	*/
+	/*	config_req.Header.PageLength = 0;	*/
+	config_req.Header.PageNumber = 0;
+	config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
+	/*	config_req.PageAddress = 0;		*/
+	config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
+			((MPI_SGE_FLAGS_LAST_ELEMENT |
+			  MPI_SGE_FLAGS_END_OF_BUFFER |
+			  MPI_SGE_FLAGS_END_OF_LIST |
+			  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+			  MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+			  MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+			  MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
+			(u32)data_sz
+	);
+	page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE);
+	config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma);
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n",
+			ioc->name));
+
+	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
+				reply_sz, (u16*)&config_reply);
+	pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
+	if (i != 0)
+		return i;
+
+	/*  Now byte swap the necessary LANPage0 fields  */
+
+/* LANPage1 */
+	/*  Immediate destination (reply area)...  */
+	reply_sz = sizeof(config_reply);
+	memset(&config_reply, 0, reply_sz);
+
+	/*  Ultimate destination...  */
+	page1 = &ioc->lan_cnfg_page1;
+	data_sz = sizeof(*page1);
+	memset(page1, 0, data_sz);
+
+	/*  Request area (config_req on the stack right now!)  */
+	req_sz = sizeof(config_req);
+	memset(&config_req, 0, req_sz);
+	config_req.Function = MPI_FUNCTION_CONFIG;
+	config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	/*	config_req.Header.PageVersion = 0;	*/
+	/*	config_req.Header.PageLength = 0;	*/
+	config_req.Header.PageNumber = 1;
+	config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
+	/*	config_req.PageAddress = 0;		*/
+	config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
+			((MPI_SGE_FLAGS_LAST_ELEMENT |
+			  MPI_SGE_FLAGS_END_OF_BUFFER |
+			  MPI_SGE_FLAGS_END_OF_LIST |
+			  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+			  MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+			  MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+			  MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
+			(u32)data_sz
+	);
+	page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE);
+	config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma);
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n",
+			ioc->name));
+
+	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
+				reply_sz, (u16*)&config_reply);
+	pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
+	if (i != 0)
+		return i;
+
+	/*  Now byte swap the necessary LANPage1 fields  */
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	SendEventNotification - Send EventNotification (on or off) request
+ *	to MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@EvSwitch: Event switch flags
+ */
+static int
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+{
+	EventNotification_t	*evnp;
+
+	evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
+	if (evnp == NULL) {
+		dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n",
+				ioc->name));
+		return 0;
+	}
+	memset(evnp, 0, sizeof(*evnp));
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+
+	evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+	evnp->ChainOffset = 0;
+	evnp->MsgFlags = 0;
+	evnp->Switch = EvSwitch;
+
+	mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp);
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	SendEventAck - Send EventAck request to MPT adapter.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@evnp: Pointer to original EventNotification request
+ */
+static int
+SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
+{
+	EventAck_t	*pAck;
+
+	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+		printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n",
+				ioc->name);
+		return -1;
+	}
+	memset(pAck, 0, sizeof(*pAck));
+
+	dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name));
+
+	pAck->Function     = MPI_FUNCTION_EVENT_ACK;
+	pAck->ChainOffset  = 0;
+	pAck->MsgFlags     = 0;
+	pAck->Event        = evnp->Event;
+	pAck->EventContext = evnp->EventContext;
+
+	mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck);
+
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS		/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
+
+#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \
+{ \
+	len -= off;			\
+	if (len < count) {		\
+		*eof = 1;		\
+		if (len <= 0)		\
+			return 0;	\
+	} else				\
+		len = count;		\
+	*start = page + off;		\
+	return len;			\
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_create(void)
+{
+	MPT_ADAPTER *ioc;
+	struct proc_dir_entry *ent;
+	int errcnt = 0;
+
+	/*
+	 * 	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+	 * 	(single level) to multi level (e.g. "driver/message/fusion")
+	 * 	something here needs to change.  -sralston
+	 */
+	procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL);
+	if (procmpt_root_dir == NULL)
+		return -ENOTDIR;
+
+	if ((ioc = mpt_adapter_find_first()) != NULL) {
+		ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL);
+		if (ent == NULL) {
+			printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n",
+					MPT_PROCFS_SUMMARY_PATHNAME);
+			errcnt++;
+		}
+	}
+
+	while (ioc != NULL) {
+		char pname[32];
+		int namelen;
+		/*
+		 *  Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
+		 */
+		namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+		if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) {
+			/*
+			 *  And populate it with: "summary" and "dbg" file entries.
+			 */
+			(void) sprintf(pname+namelen, "/summary");
+			ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc);
+			if (ent == NULL) {
+				errcnt++;
+				printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+						ioc->name, pname);
+			}
+//#ifdef MPT_DEBUG
+			/* DEBUG aid! */
+			(void) sprintf(pname+namelen, "/dbg");
+			ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc);
+			if (ent == NULL) {
+				errcnt++;
+				printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+						ioc->name, pname);
+			}
+//#endif
+		} else {
+			errcnt++;
+			printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+					ioc->name, pname);
+
+		}
+
+		ioc = mpt_adapter_find_next(ioc);
+	}
+
+	if (errcnt) {
+//		remove_proc_entry("mpt", 0);
+		return -ENOTDIR;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_destroy(void)
+{
+	MPT_ADAPTER *ioc;
+
+	/*
+	 * 	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+	 * 	(single level) to multi level (e.g. "driver/message/fusion")
+	 * 	something here needs to change.  -sralston
+	 */
+
+	ioc = mpt_adapter_find_first();
+	if (ioc != NULL) {
+		remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0);
+	}
+
+	while (ioc != NULL) {
+		char pname[32];
+		int namelen;
+		/*
+		 *  Tear down each "/proc/mpt/iocN" subdirectory.
+		 */
+		namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+		(void) sprintf(pname+namelen, "/summary");
+		remove_proc_entry(pname, 0);
+//#ifdef MPT_DEBUG
+		(void) sprintf(pname+namelen, "/dbg");
+		remove_proc_entry(pname, 0);
+//#endif
+		(void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+		remove_proc_entry(pname, 0);
+
+		ioc = mpt_adapter_find_next(ioc);
+	}
+
+	if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
+		remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
+		return 0;
+	}
+
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	procmpt_read_summary - Handle read request from /proc/mpt/summary
+ *	or from /proc/mpt/iocN/summary.
+ *	@page: Pointer to area to write information
+ *	@start: Pointer to start pointer
+ *	@off: Offset to start writing
+ *	@count: 
+ *	@eof: Pointer to EOF integer
+ *	@data: Pointer 
+ *
+ *	Returns numbers of characters written to process performing the read.
+ */
+static int
+procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	MPT_ADAPTER *ioc;
+	char *out = page;
+	int len;
+
+	if (data == NULL)
+		ioc = mpt_adapter_find_first();
+	else
+		ioc = data;
+
+// Too verbose!
+//	out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none");
+
+	while (ioc) {
+		int	more = 0;
+
+// Too verbose!
+//		mpt_print_ioc_facts(ioc, out, &more, 0);
+		mpt_print_ioc_summary(ioc, out, &more, 0);
+
+		out += more;
+		if ((out-page) >= count) {
+			break;
+		}
+
+		if (data == NULL)
+			ioc = mpt_adapter_find_next(ioc);
+		else
+			ioc = NULL;				/* force exit for iocN */
+	}
+	len = out - page;
+
+	PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+}
+
+// debug aid!
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg.
+ *	@page: Pointer to area to write information
+ *	@start: Pointer to start pointer
+ *	@off: Offset to start writing
+ *	@count: 
+ *	@eof: Pointer to EOF integer
+ *	@data: Pointer 
+ *
+ *	Returns numbers of characters written to process performing the read.
+ */
+static int
+procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	MPT_ADAPTER *ioc;
+	char *out = page;
+	int len;
+
+	ioc = data;
+
+	while (ioc) {
+		int	more = 0;
+
+		mpt_print_ioc_facts(ioc, out, &more, 0);
+
+		out += more;
+		if ((out-page) >= count) {
+			break;
+		}
+		ioc = NULL;
+	}
+	len = out - page;
+
+	PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif		/* CONFIG_PROC_FS } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
+{
+	if ((ioc->facts0.FWVersion & 0xF000) == 0xE000)
+		sprintf(buf, " (Exp %02d%02d)",
+			(ioc->facts0.FWVersion & 0x0F00) >> 8,	/* Month */
+			ioc->facts0.FWVersion & 0x001F);	/* Day */
+	else
+		buf[0] ='\0';
+
+	/* insider hack! */
+	if (ioc->facts0.FWVersion & 0x0080) {
+		strcat(buf, " [MDBG]");
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@buffer: Pointer to buffer where IOC summary info should be written
+ *	@size: Pointer to number of bytes we wrote (set by this routine)
+ *	@len: Offset at which to start writing in buffer
+ *
+ * 	This routine writes (english readable) ASCII text, which represents
+ * 	a summary of IOC information, to a buffer.
+ */
+void
+mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+{
+	char expVer[32];
+	int y;
+
+
+	mpt_get_fw_exp_ver(expVer, ioc);
+
+	/*
+	 *  Shorter summary of attached ioc's...
+	 */
+	y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d",
+			ioc->name,
+			ioc->prod_name,
+			MPT_FW_REV_MAGIC_ID_STRING,	/* "FwRev=" or somesuch */
+			ioc->facts0.FWVersion,
+			expVer,
+			ioc->facts0.NumberOfPorts,
+			ioc->req_depth);
+
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+		u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+		y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
+			a[5], a[4], a[3], a[2], a[1], a[0]);
+	}
+
+	if (!ioc->active)
+		y += sprintf(buffer+len+y, " (disabled)");
+
+	y += sprintf(buffer+len+y, "\n");
+
+	*size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@buffer: Pointer to buffer where IOC facts should be written
+ *	@size: Pointer to number of bytes we wrote (set by this routine)
+ *	@len: Offset at which to start writing in buffer
+ *
+ * 	This routine writes (english readable) ASCII text, which represents
+ * 	a summary of the IOC facts, to a buffer.
+ */
+void
+mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+{
+	char expVer[32];
+	char iocName[16];
+	int sz;
+	int y;
+
+
+	mpt_get_fw_exp_ver(expVer, ioc);
+
+	strcpy(iocName, ioc->name);
+	y = sprintf(buffer+len, "%s:\n", iocName);
+
+	y += sprintf(buffer+len+y, "  ProductID = 0x%04x\n", ioc->facts0.ProductID);
+	y += sprintf(buffer+len+y, "  PortNumber = %d (of %d)\n",
+		ioc->pfacts0.PortNumber+1,
+		ioc->facts0.NumberOfPorts);
+	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+		u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+		y += sprintf(buffer+len+y, "  LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+			a[5], a[4], a[3], a[2], a[1], a[0]);
+	}
+	y += sprintf(buffer+len+y, "  FWVersion = 0x%04x%s\n", ioc->facts0.FWVersion, expVer);
+	y += sprintf(buffer+len+y, "  MsgVersion = 0x%04x\n", ioc->facts0.MsgVersion);
+	y += sprintf(buffer+len+y, "  WhoInit = 0x%02x\n", ioc->facts0.WhoInit);
+	y += sprintf(buffer+len+y, "  EventState = 0x%02x\n", ioc->facts0.EventState);
+	y += sprintf(buffer+len+y, "  CurrentHostMfaHighAddr = 0x%08x\n",
+		 	ioc->facts0.CurrentHostMfaHighAddr);
+	y += sprintf(buffer+len+y, "  CurrentSenseBufferHighAddr = 0x%08x\n",
+			ioc->facts0.CurrentSenseBufferHighAddr);
+	y += sprintf(buffer+len+y, "  MaxChainDepth = 0x%02x frames\n", ioc->facts0.MaxChainDepth);
+	y += sprintf(buffer+len+y, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts0.BlockSize);
+
+	y += sprintf(buffer+len+y, "  RequestFrames @ 0x%p (Dma @ 0x%08x)\n",
+					ioc->req_alloc, ioc->req_alloc_dma);
+	/*
+	 *  Rounding UP to nearest 4-kB boundary here...
+	 */
+	sz = (ioc->req_sz * ioc->req_depth) + 128;
+	sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+	y += sprintf(buffer+len+y, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+					ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+	y += sprintf(buffer+len+y, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
+					4*ioc->facts0.RequestFrameSize,
+					ioc->facts0.GlobalCredits);
+
+	y += sprintf(buffer+len+y, "  ReplyFrames   @ 0x%p (Dma @ 0x%08x)\n",
+					ioc->reply_alloc, ioc->reply_alloc_dma);
+	sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+	y += sprintf(buffer+len+y, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+					ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+	y += sprintf(buffer+len+y, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
+					ioc->factsN.CurReplyFrameSize,
+					ioc->facts0.ReplyQueueDepth);
+
+	*size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static char *
+EventDescriptionStr(u8 event, u32 evData0)
+{
+	char *ds = NULL;
+
+	switch(event) {
+	case MPI_EVENT_NONE:
+		ds = "None";
+		break;
+	case MPI_EVENT_LOG_DATA:
+		ds = "Log Data";
+		break;
+	case MPI_EVENT_STATE_CHANGE:
+		ds = "State Change";
+		break;
+	case MPI_EVENT_UNIT_ATTENTION:
+		ds = "Unit Attention";
+		break;
+	case MPI_EVENT_IOC_BUS_RESET:
+		ds = "IOC Bus Reset";
+		break;
+	case MPI_EVENT_EXT_BUS_RESET:
+		ds = "External Bus Reset";
+		break;
+	case MPI_EVENT_RESCAN:
+		ds = "Bus Rescan Event"; 
+		/* Ok, do we need to do anything here? As far as
+		   I can tell, this is when a new device gets added
+		   to the loop. */
+		break;
+	case MPI_EVENT_LINK_STATUS_CHANGE:
+		if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
+			ds = "Link Status(FAILURE) Change";
+		else
+			ds = "Link Status(ACTIVE) Change";
+		break;
+	case MPI_EVENT_LOOP_STATE_CHANGE:
+		if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
+			ds = "Loop State(LIP) Change";
+		else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
+			ds = "Loop State(LPE) Change";			/* ??? */
+		else
+			ds = "Loop State(LPB) Change";			/* ??? */
+		break;
+	case MPI_EVENT_LOGOUT:
+		ds = "Logout";
+		break;
+	case MPI_EVENT_EVENT_CHANGE:
+		if (evData0)
+			ds = "Events(ON) Change";
+		else
+			ds = "Events(OFF) Change";
+		break;
+	/*
+	 *  MPT base "custom" events may be added here...
+	 */
+	default:
+		ds = "Unknown";
+		break;
+	}
+	return ds;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	ProcessEventNotification - Route a received EventNotificationReply to
+ *	all currently regeistered event handlers.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@pEventReply: Pointer to EventNotification reply frame
+ *	@evHandlers: Pointer to integer, number of event handlers
+ *
+ *	Returns sum of event handlers return values.
+ */
+static int
+ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
+{
+	u16 evDataLen;
+	u32 evData0 = 0;
+//	u32 evCtx;
+	int i;
+	int r = 0;
+	int handlers = 0;
+	char *evStr;
+	u8 event;
+
+	/*
+	 *  Do platform normalization of values
+	 */
+	event = le32_to_cpu(pEventReply->Event) & 0xFF;
+//	evCtx = le32_to_cpu(pEventReply->EventContext);
+	evDataLen = le16_to_cpu(pEventReply->EventDataLength);
+	if (evDataLen) {
+		evData0 = le32_to_cpu(pEventReply->Data[0]);
+	}
+
+	evStr = EventDescriptionStr(event, evData0);
+	dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n",
+			ioc->name,
+			evStr,
+			event));
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
+	printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
+	for (i = 0; i < evDataLen; i++)
+		printk(" %08x", le32_to_cpu(pEventReply->Data[i]));
+	printk("\n");
+#endif
+
+	/*
+	 *  Do general / base driver event processing
+	 */
+	switch(event) {
+	case MPI_EVENT_NONE:			/* 00 */
+	case MPI_EVENT_LOG_DATA:		/* 01 */
+	case MPI_EVENT_STATE_CHANGE:		/* 02 */
+	case MPI_EVENT_UNIT_ATTENTION:		/* 03 */
+	case MPI_EVENT_IOC_BUS_RESET:		/* 04 */
+	case MPI_EVENT_EXT_BUS_RESET:		/* 05 */
+	case MPI_EVENT_RESCAN:			/* 06 */
+	case MPI_EVENT_LINK_STATUS_CHANGE:	/* 07 */
+	case MPI_EVENT_LOOP_STATE_CHANGE:	/* 08 */
+	case MPI_EVENT_LOGOUT:			/* 09 */
+	default:
+		break;
+	case MPI_EVENT_EVENT_CHANGE:		/* 0A */
+		if (evDataLen) {
+			u8 evState = evData0 & 0xFF;
+
+			/* CHECKME! What if evState unexpectedly says OFF (0)? */
+
+			/* Update EventState field in cached IocFacts */
+			if (ioc->factsN.Function) {
+				ioc->factsN.EventState = evState;
+			}
+		}
+		break;
+	}
+
+	/*
+	 *  Call each currently registered protocol event handler.
+	 */
+	for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+		if (MptEvHandlers[i]) {
+			dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n",
+					ioc->name, i));
+			r += (*(MptEvHandlers[i]))(ioc, pEventReply);
+			handlers++;
+		}
+	}
+	/* FIXME?  Examine results here? */
+
+	/*
+	 *  If needed, send (a single) EventAck.
+	 */
+	if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
+		if ((i = SendEventAck(ioc, pEventReply)) != 0) {
+		}
+	}
+
+	*evHandlers = handlers;
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_fc_log_info - Log information returned from Fibre Channel IOC.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@log_info: U32 LogInfo reply word from the IOC
+ *
+ *	Refer to lsi/fc_log.h.
+ */
+static void
+mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+	static char *subcl_str[8] = {
+		"FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
+		"FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
+	};
+	char *desc = "unknown";
+	u8 subcl = (log_info >> 24) & 0x7;
+	u32 SubCl = log_info & 0x27000000;
+
+	switch(log_info) {
+/* FCP Initiator */
+    	case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+		desc = "Received an out of order frame - unsupported";
+		break;
+	case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
+		desc = "Bad start of frame primative";
+		break;
+	case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME:
+		desc = "Bad end of frame primative";
+		break;
+	case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN:
+		desc = "Receiver hardware detected overrun";
+		break;
+	case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER:
+		desc = "Other errors caught by IOC which require retries";
+		break;
+	case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD:
+		desc = "Main processor could not initialize sub-processor";
+		break;
+/* FC Target */
+	case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC:
+		desc = "Not sent because we are waiting for a PDISC from the initiator";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN:
+		desc = "Not sent because we are not logged in to the remote node";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP:
+		desc = "Data Out, Auto Response, not sent due to a LIP";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP:
+		desc = "Data In, Auto Response, not sent due to a LIP";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA:
+		desc = "Data In, Auto Response, missing data frames";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP:
+		desc = "Data Out, No Response, not sent due to a LIP";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP:
+		desc = "Auto-response after a write not sent due to a LIP";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP:
+		desc = "Data In, No Response, not completed due to a LIP";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA:
+		desc = "Data In, No Response, missing data frames";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP:
+		desc = "Manual Response not sent due to a LIP";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3:
+		desc = "Not sent because remote node does not support Class 3";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID:
+		desc = "Not sent because login to remote node not validated";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
+		desc = "Cleared from the outbound after a logout";
+		break;
+	case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
+		desc = "Cleared waiting for data after a logout";
+		break;
+/* LAN */
+	case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING:
+		desc = "Transaction Context Sgl Missing";
+		break;
+	case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE:
+		desc = "Transaction Context found before an EOB";
+		break;
+	case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET:
+		desc = "Transaction Context value has reserved bits set";
+		break;
+	case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG:
+		desc = "Invalid SGL Flags";
+		break;
+/* FC Link */
+	case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT:
+		desc = "Loop initialization timed out";
+		break;
+	case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED:
+		desc = "Another system controller already initialized the loop";
+		break;
+	case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
+		desc = "Not synchronized to signal or still negotiating (possible cable problem)";
+		break;
+	}
+
+	printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
+			ioc->name, log_info, subcl_str[subcl]);
+	if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
+		printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
+	else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE)
+		printk("\n");		/* StateChg in LogInfo & 0x00FFFFFF, above */
+	else
+		printk("\n" KERN_INFO " %s\n", desc);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mr: Pointer to MPT reply frame
+ *	@log_info: U32 LogInfo word from the IOC
+ *
+ *	Refer to lsi/sp_log.h.
+ */
+static void
+mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+	/* FIXME! */
+	printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI
+ *	OpCode strings from the (optional) isense module.
+ *	@ascqTable: Pointer to ASCQ_Table_t structure
+ *	@ascqtbl_sz: Number of entries in ASCQ_Table
+ *	@opsTable: Pointer to array of SCSI OpCode strings (char pointers)
+ *
+ *	Specialized driver registration routine for the isense driver.
+ */
+int
+mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable)
+{
+	int r = 0;
+
+	if (ascqTable && ascqtbl_sz && opsTable) {
+		mpt_v_ASCQ_TablePtr = ascqTable;
+		mpt_ASCQ_TableSz = ascqtbl_sz;
+		mpt_ScsiOpcodesPtr = opsTable;
+		printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+		r = 1;
+	}
+	MOD_INC_USE_COUNT;
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI
+ *	OpCode strings from the isense driver.
+ *
+ *	Specialized driver deregistration routine for the isense driver.
+ */
+void
+mpt_deregister_ascqops_strings(void)
+{
+	mpt_v_ASCQ_TablePtr = NULL;
+	mpt_ASCQ_TableSz = 0;
+	mpt_ScsiOpcodesPtr = NULL;
+	printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+	MOD_DEC_USE_COUNT;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+EXPORT_SYMBOL(mpt_register);
+EXPORT_SYMBOL(mpt_deregister);
+EXPORT_SYMBOL(mpt_event_register);
+EXPORT_SYMBOL(mpt_event_deregister);
+EXPORT_SYMBOL(mpt_get_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_free_msg_frame);
+EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_adapter_find_first);
+EXPORT_SYMBOL(mpt_adapter_find_next);
+EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_print_ioc_summary);
+EXPORT_SYMBOL(mpt_lan_index);
+EXPORT_SYMBOL(mpt_stm_index);
+
+EXPORT_SYMBOL(mpt_register_ascqops_strings);
+EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
+EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr);
+EXPORT_SYMBOL(mpt_ASCQ_TableSz);
+EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	fusion_init - Fusion MPT base driver initialization routine.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+int __init fusion_init(void)
+{
+	int i;
+
+	if (FusionInitCalled++) {
+		dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n"));
+		return 0;
+	}
+
+	show_mptmod_ver(my_NAME, my_VERSION);
+	printk(KERN_INFO COPYRIGHT "\n");
+
+	Q_INIT(&MptAdapters, MPT_ADAPTER);			/* set to empty */
+	for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
+		MptCallbacks[i] = NULL;
+		MptDriverClass[i] = MPTUNKNOWN_DRIVER;
+		MptEvHandlers[i] = NULL;
+	}
+
+	/* NEW!  20010120 -sralston
+	 *  Register ourselves (mptbase) in order to facilitate
+	 *  EventNotification handling.
+	 */
+	mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+
+	if ((i = mpt_pci_scan()) < 0)
+		return i;
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	fusion_exit - Perform driver unload cleanup.
+ *
+ *	This routine frees all resources associated with each MPT adapter
+ *	and removes all %MPT_PROCFS_MPTBASEDIR entries.
+ */
+static void fusion_exit(void)
+{
+	MPT_ADAPTER *this;
+	int i;
+
+	dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
+
+	/*
+	 *  Paranoia; disable interrupts on all MPT adapters.
+	 */
+	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+		if ((this = mpt_adapters[i]) != NULL) {
+			/* Disable adapter interrupts! */
+			CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+			/* Clear any lingering interrupt */
+			CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+			this->active = 0;
+		}
+	}
+
+	/* Whups?  20010120 -sralston
+	 *  Moved this *above* removal of all MptAdapters!
+	 */
+#ifdef CONFIG_PROC_FS
+	procmpt_destroy();
+#endif
+
+	while (! Q_IS_EMPTY(&MptAdapters)) {
+		this = MptAdapters.head;
+		Q_DEL_ITEM(this);
+		mpt_adapter_dispose(this);
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(fusion_init);
+module_exit(fusion_exit);
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptbase.h linux/drivers/message/fusion/mptbase.h
--- v2.4.6/linux/drivers/message/fusion/mptbase.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptbase.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,581 @@
+/*
+ *  linux/drivers/message/fusion/mptbase.h
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *     (see mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptbase.h,v 1.38 2001/03/22 10:54:30 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef MPTBASE_H_INCLUDED
+#define MPTBASE_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux_compat.h"	/* linux-2.2.x (vs. -2.4.x) tweaks */
+
+#include "lsi/mpi_type.h"
+#include "lsi/mpi.h"		/* Fusion MPI(nterface) basic defs */
+#include "lsi/mpi_ioc.h"	/* Fusion MPT IOC(ontroller) defs */
+#include "lsi/mpi_cnfg.h"	/* IOC configuration support */
+#include "lsi/mpi_init.h"	/* SCSI Host (initiator) protocol support */
+#include "lsi/mpi_lan.h"	/* LAN over FC protocol support */
+
+//#include "lsi/mpi_fc.h"	/* Fibre Channel (lowlevel) support */
+//#include "lsi/mpi_targ.h"	/* SCSI/FCP Target protcol support */
+#include "lsi/fc_log.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef MODULEAUTHOR
+#define MODULEAUTHOR	"LSI Logic Corporation"
+#endif
+
+#ifndef COPYRIGHT
+#define COPYRIGHT	"Copyright (c) 1999-2001 " MODULEAUTHOR
+#endif
+
+#define MPT_LINUX_VERSION_COMMON	"1.00.11"
+#define MPT_LINUX_VERSION_EXP		"0.09.66-EXP"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-1.00.11"
+#define WHAT_MAGIC_STRING		"@" "(" "#" ")"
+
+#define show_mptmod_ver(s,ver)  \
+	printk(KERN_INFO "%s %s\n", s, ver);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Fusion MPT(linux) driver configurable stuff...
+ */
+#define MPT_MAX_ADAPTERS		16
+#define MPT_MAX_PROTOCOL_DRIVERS	8
+
+#define MPT_MISCDEV_BASENAME		"mptctl"
+#define MPT_MISCDEV_PATHNAME		"/dev/" MPT_MISCDEV_BASENAME
+
+#define MPT_PROCFS_MPTBASEDIR		"mpt"
+						/* chg it to "driver/fusion" ? */
+#define MPT_PROCFS_SUMMARY_NODE		MPT_PROCFS_MPTBASEDIR "/summary"
+#define MPT_PROCFS_SUMMARY_PATHNAME	"/proc/" MPT_PROCFS_SUMMARY_NODE
+#define MPT_FW_REV_MAGIC_ID_STRING	"FwRev="
+
+#ifdef __KERNEL__	/* { */
+#define  MPT_MAX_REQ_DEPTH		1023
+#define  MPT_REQ_DEPTH			256
+#define  MPT_MIN_REQ_DEPTH		128
+
+#define  MPT_MAX_REPLY_DEPTH		MPT_MAX_REQ_DEPTH
+#define  MPT_REPLY_DEPTH		128
+#define  MPT_MIN_REPLY_DEPTH		8
+#define  MPT_MAX_REPLIES_PER_ISR	32
+
+#define  MPT_MAX_FRAME_SIZE		128
+#define  MPT_REQ_SIZE			128
+#define  MPT_REPLY_SIZE			128
+
+#define  MPT_SG_BUCKETS_PER_HUNK	1
+
+#ifdef MODULE
+#define  MPT_REQ_DEPTH_RANGE_STR	__MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH)
+#define  MPT_REPLY_DEPTH_RANGE_STR	__MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH)
+#define  MPT_REPLY_SIZE_RANGE_STR	__MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  MPT protocol driver defs...
+ */
+typedef enum {
+	MPTBASE_DRIVER,		/* MPT base class */
+	MPTCTL_DRIVER,		/* MPT ioctl class */
+	MPTSCSIH_DRIVER,	/* MPT SCSI host (initiator) class */
+	MPTLAN_DRIVER,		/* MPT LAN class */
+	MPTSTM_DRIVER,		/* MPT SCSI target mode class */
+	MPTUNKNOWN_DRIVER
+} MPT_DRIVER_CLASS;
+
+/*
+ *  MPT adapter / port / bus / device info structures...
+ */
+
+typedef union _MPT_FRAME_TRACKER {
+	struct {
+		struct _MPT_FRAME_HDR	*forw;
+		struct _MPT_FRAME_HDR	*back;
+		u32			 arg1;
+		void			*argp1;
+	} linkage;
+	/*
+	 * NOTE: On non-32-bit systems, where pointers are LARGE,
+	 * using the linkage pointers destroys our sacred MsgContext
+	 * field contents.  But we don't care anymore because these
+	 * are now reset in mpt_put_msg_frame() just prior to sending
+	 * a request off to the IOC.
+	 */
+	struct {
+		u32 __hdr[2];
+		/*
+		 * The following _MUST_ match the location of the
+		 * MsgContext field in the MPT message headers.
+		 */
+		union {
+			u32		 MsgContext;
+			struct {
+				u16	 req_idx;	/* Request index */
+				u8	 cb_idx;	/* callback function index */
+				u8	 rsvd;
+			} fld;
+		} msgctxu;
+	} hwhdr;
+} MPT_FRAME_TRACKER;
+
+/*
+ *  We might want to view/access a frame as:
+ *    1) generic request header
+ *    2) SCSIIORequest
+ *    3) SCSIIOReply
+ *    4) MPIDefaultReply
+ *    5) frame tracker
+ */
+typedef struct _MPT_FRAME_HDR {
+	union {
+		MPIHeader_t		hdr;
+		SCSIIORequest_t		scsireq;
+		SCSIIOReply_t		sreply;
+		MPIDefaultReply_t	reply;
+		MPT_FRAME_TRACKER	frame;
+	} u;
+} MPT_FRAME_HDR;
+
+typedef struct _MPT_Q_TRACKER {
+	MPT_FRAME_HDR	*head;
+	MPT_FRAME_HDR	*tail;
+} MPT_Q_TRACKER;
+
+
+typedef struct _MPT_SGL_HDR {
+	SGESimple32_t	 sge[1];
+} MPT_SGL_HDR;
+
+typedef struct _MPT_SGL64_HDR {
+	SGESimple64_t	 sge[1];
+} MPT_SGL64_HDR;
+
+
+typedef struct _Q_ITEM {
+	struct _Q_ITEM	*forw;
+	struct _Q_ITEM	*back;
+} Q_ITEM;
+
+typedef struct _Q_TRACKER {
+	struct _Q_ITEM	*head;
+	struct _Q_ITEM	*tail;
+} Q_TRACKER;
+
+
+/*
+ *  Chip-specific stuff...
+ */
+
+typedef enum {
+	FC909 = 0x0909,
+	FC919 = 0x0919,
+	FC929 = 0x0929,
+	C1030 = 0x1030,
+	FCUNK = 0xFBAD
+} CHIP_TYPE;
+
+/*
+ *  System interface register set
+ */
+
+typedef struct _SYSIF_REGS
+{
+	u32	Doorbell;	/* 00     System<->IOC Doorbell reg  */
+	u32	WriteSequence;	/* 04     Write Sequence register    */
+	u32	Diagnostic;	/* 08     Diagnostic register        */
+	u32	TestBase;	/* 0C     Test Base Address          */
+	u32	Reserved1[8];	/* 10-2F  reserved for future use    */
+	u32	IntStatus;	/* 30     Interrupt Status           */
+	u32	IntMask;	/* 34     Interrupt Mask             */
+	u32	Reserved2[2];	/* 38-3F  reserved for future use    */
+	u32	RequestFifo;	/* 40     Request Post/Free FIFO     */
+	u32	ReplyFifo;	/* 44     Reply   Post/Free FIFO     */
+	u32	Reserved3[2];	/* 48-4F  reserved for future use    */
+	u32	HostIndex;	/* 50     Host Index register        */
+	u32	Reserved4[15];	/* 54-8F                             */
+	u32	Fubar;		/* 90     For Fubar usage            */
+	u32	Reserved5[27];	/* 94-FF                             */
+} SYSIF_REGS;
+
+/*
+ * NOTE: Use MPI_{DOORBELL,WRITESEQ,DIAG}_xxx defs in lsi/mpi.h
+ * in conjunction with SYSIF_REGS accesses!
+ */
+
+
+typedef struct _MPT_ADAPTER
+{
+	struct _MPT_ADAPTER	*forw;
+	struct _MPT_ADAPTER	*back;
+	int			 id;		/* Unique adapter id {0,1,2,...} */
+	int			 pci_irq;
+	IOCFactsReply_t		 facts0;
+	IOCFactsReply_t		 factsN;
+	char			 name[32];	/* "iocN"             */
+	char			*prod_name;	/* "LSIFC9x9"         */
+	u32			 mem_phys;	/* == f4020000 (mmap) */
+	volatile SYSIF_REGS	*chip;		/* == c8817000 (mmap) */
+	CHIP_TYPE		 chip_type;
+	int			 mem_size;
+	int			 alloc_total;
+	u32			 last_state;
+	int			 active;
+	int			 sod_reset;
+	unsigned long		 last_kickstart;
+	PortFactsReply_t	 pfacts0;
+	PortFactsReply_t	 pfactsN;
+	LANPage0_t		 lan_cnfg_page0;
+	LANPage1_t		 lan_cnfg_page1;
+	u8			*reply_alloc;		/* Reply frames alloc ptr */
+	dma_addr_t		 reply_alloc_dma;
+	MPT_FRAME_HDR		*reply_frames;		/* Reply frames - rounded up! */
+	dma_addr_t		 reply_frames_dma;
+	int			 reply_depth;
+	int			 reply_sz;
+		/* We (host driver) get to manage our own RequestQueue! */
+	u8			*req_alloc;		/* Request frames alloc ptr */
+	dma_addr_t		 req_alloc_dma;
+	MPT_FRAME_HDR		*req_frames;		/* Request msg frames for PULL mode! */
+	dma_addr_t		 req_frames_dma;
+	int			 req_depth;
+	int			 req_sz;
+	spinlock_t		 FreeQlock;
+	MPT_Q_TRACKER		 FreeQ;
+		/* Pool of SCSI sense buffers for commands coming from
+		 * the SCSI mid-layer.  We have one 256 byte sense buffer
+		 * for each REQ entry.
+		 */
+	u8			*sense_buf_pool;
+	dma_addr_t		 sense_buf_pool_dma;
+	int			 hs_reply_idx;
+	u32			 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
+	u16			 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
+	struct pci_dev		*pcidev;
+	struct _MPT_ADAPTER	*alt_ioc;
+/*	atomic_t		 userCnt;	*/
+	u8			*memmap;
+	int			 mtrr_reg;
+	struct Scsi_Host	*sh;
+	struct proc_dir_entry	*ioc_dentry;
+} MPT_ADAPTER;
+
+
+typedef struct _MPT_ADAPTER_TRACKER {
+	MPT_ADAPTER	*head;
+	MPT_ADAPTER	*tail;
+} MPT_ADAPTER_TRACKER;
+
+/*
+ *  New return value convention:
+ *    1 = Ok to free associated request frame
+ *    0 = not Ok ...
+ */
+typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply);
+
+/*
+ *  Fibre Channel (SCSI) target device...
+ */
+typedef struct _FC_TARGET {
+	struct _FC_TARGET	*forw;
+	struct _FC_TARGET	*back;
+	int			 bus_id;
+	int			 target_id;
+	int			 lun_exists[32];
+	u8			 inquiry_data[36];
+	u8			 last_sense[256];
+} FC_TARGET;
+
+typedef struct _FCDEV_TRACKER {
+	FC_TARGET	*head;
+	FC_TARGET	*tail;
+} FCDEV_TRACKER;
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Funky (private) macros...
+ */
+#ifdef MPT_DEBUG
+#define dprintk(x)  printk x
+#else
+#define dprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_HANDSHAKE
+#define dhsprintk(x)  printk x
+#else
+#define dhsprintk(x)
+#endif
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define dmfprintk(x)  printk x
+#else
+#define dmfprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_IRQ
+#define dirqprintk(x)  printk x
+#else
+#define dirqprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_EVENTS
+#define deventprintk(x)  printk x
+#else
+#define deventprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SPINLOCK
+#define dslprintk(x)  printk x
+#else
+#define dslprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SG
+#define dsgprintk(x)  printk x
+#else
+#define dsgprintk(x)
+#endif
+
+
+#define MPT_INDEX_2_MFPTR(ioc,idx) \
+	(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
+
+#define MFPTR_2_MPT_INDEX(ioc,mf) \
+	(int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz )
+
+#define Q_INIT(q,type)  (q)->head = (q)->tail = (type*)(q)
+#define Q_IS_EMPTY(q)   ((Q_ITEM*)(q)->head == (Q_ITEM*)(q))
+
+#define Q_ADD_TAIL(qt,i,type) { \
+	Q_TRACKER	*_qt = (Q_TRACKER*)(qt); \
+	Q_ITEM		*oldTail = _qt->tail; \
+	(i)->forw = (type*)_qt; \
+	(i)->back = (type*)oldTail; \
+	oldTail->forw = (Q_ITEM*)(i); \
+	_qt->tail = (Q_ITEM*)(i); \
+}
+
+#define Q_ADD_HEAD(qt,i,type) { \
+	Q_TRACKER	*_qt = (Q_TRACKER*)(qt); \
+	Q_ITEM		*oldHead = _qt->head; \
+	(i)->forw = (type*)oldHead; \
+	(i)->back = (type*)_qt; \
+	oldHead->back = (Q_ITEM*)(i); \
+	_qt->head = (Q_ITEM*)(i); \
+}
+
+#define Q_DEL_ITEM(i) { \
+	Q_ITEM  *_forw = (Q_ITEM*)(i)->forw; \
+	Q_ITEM  *_back = (Q_ITEM*)(i)->back; \
+	_back->forw = _forw; \
+	_forw->back = _back; \
+}
+
+
+#define SWAB4(value) \
+	(u32)(   (((value) & 0x000000ff) << 24) \
+	       | (((value) & 0x0000ff00) << 8)  \
+	       | (((value) & 0x00ff0000) >> 8)  \
+	       | (((value) & 0xff000000) >> 24) )
+
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define DBG_DUMP_REPLY_FRAME(mfp) \
+	{	u32 *m = (u32 *)(mfp);					\
+		int  i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16;	\
+		printk(KERN_INFO " ");					\
+		for (i=0; i<n; i++)					\
+			printk(" %08x", le32_to_cpu(m[i]));		\
+		printk("\n");						\
+	}
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \
+	{	int  i, n = 3;						\
+		u32 *m = (u32 *)(mfp);					\
+		printk(KERN_INFO " ");					\
+		for (i=0; i<n; i++)					\
+			printk(" %08x", le32_to_cpu(m[i]));		\
+		printk("\n");						\
+	}
+#else
+#define DBG_DUMP_REPLY_FRAME(mfp)
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif		/* } __KERNEL__ */
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  MPT Control IOCTLs and structures
+ */
+#define MPT_MAGIC_NUMBER	'm'
+#define MPTRWPERF		_IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w)
+#define MPTRWPERF_CHK		_IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w)
+#define MPTRWPERF_RESET		_IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w)
+#define MPTFWDOWNLOAD		_IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
+#define MPTSCSICMD		_IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd)
+
+/*
+ *  Define something *vague* enough that caller doesn't
+ *  really need to know anything about device parameters
+ *  (blk_size, capacity, etc.)
+ */
+struct mpt_raw_r_w {
+	unsigned int	 iocnum;	/* IOC unit number */
+	unsigned int	 port;		/* IOC port number */
+	unsigned int	 target;	/* SCSI Target */
+	unsigned int	 lun;		/* SCSI LUN */
+	unsigned int	 iters;		/* N iterations */
+	unsigned short	 nblks;		/* number of blocks per IO */
+	unsigned short	 qdepth;	/* max Q depth on this device */
+	unsigned char	 range;		/* 0-100% of FULL disk capacity, 0=use (nblks X iters) */
+	unsigned char	 skip;		/* % of disk to skip */
+	unsigned char	 rdwr;		/* 0-100%, 0=pure ReaDs, 100=pure WRites */
+	unsigned char	 seqran;	/* 0-100%, 0=pure SEQential, 100=pure RANdom */
+	unsigned int	 cache_sz;	/* In Kb!  Optimize hits to N Kb cache size */
+};
+
+struct mpt_fw_xfer {
+	unsigned int	 iocnum;	/* IOC unit number */
+/*	u8		 flags;*/	/* Message flags - bit field */
+	unsigned int	 fwlen;
+	void		*bufp;		/* Pointer to firmware buffer */
+};
+
+struct mpt_scsi_cmd {
+	unsigned int	 iocnum;	/* IOC unit number */
+	unsigned int	 port;		/* IOC port number */
+	unsigned int	 target;	/* SCSI Target */
+	unsigned int	 lun;		/* SCSI LUN */
+	SCSIIORequest_t	 scsi_req;
+	SCSIIOReply_t	 scsi_reply;
+};
+
+struct mpt_ioctl_sanity {
+	unsigned int	 iocnum;
+};
+
+#ifdef __KERNEL__	/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Public entry points...
+ */
+extern int	 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void	 mpt_deregister(int cb_idx);
+extern int	 mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void	 mpt_event_deregister(int cb_idx);
+extern int	 mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable);
+extern void	 mpt_deregister_ascqops_strings(void);
+extern MPT_FRAME_HDR	*mpt_get_msg_frame(int handle, int iocid);
+extern void	 mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern void	 mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern int	 mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req);
+extern int	 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
+extern MPT_ADAPTER	*mpt_adapter_find_first(void);
+extern MPT_ADAPTER	*mpt_adapter_find_next(MPT_ADAPTER *prev);
+extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+extern void	 mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+
+/*
+ *  Public data decl's...
+ */
+extern int		  mpt_lan_index;	/* needed by mptlan.c */
+extern int		  mpt_stm_index;	/* needed by mptstm.c */
+
+extern void		 *mpt_v_ASCQ_TablePtr;
+extern const char	**mpt_ScsiOpcodesPtr;
+extern int		  mpt_ASCQ_TableSz;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif		/* } __KERNEL__ */
+
+/*
+ *  More (public) macros...
+ */
+#ifndef MIN
+#define MIN(a, b)   (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)   (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef offsetof
+#define offsetof(t, m)	((size_t) (&((t *)0)->m))
+#endif
+
+#if defined(__alpha__) || defined(__sparc_v9__)
+#define CAST_U32_TO_PTR(x)	((void *)(u64)x)
+#define CAST_PTR_TO_U32(x)	((u32)(u64)x)
+#else
+#define CAST_U32_TO_PTR(x)	((void *)x)
+#define CAST_PTR_TO_U32(x)	((u32)x)
+#endif
+
+#define MPT_PROTOCOL_FLAGS_c_c_c_c(pflags) \
+	((pflags) & MPI_PORTFACTS_PROTOCOL_INITIATOR)	? 'I' : 'i',	\
+	((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET)	? 'T' : 't',	\
+	((pflags) & MPI_PORTFACTS_PROTOCOL_LAN)		? 'L' : 'l',	\
+	((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)	? 'B' : 'b'
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptctl.c linux/drivers/message/fusion/mptctl.c
--- v2.4.6/linux/drivers/message/fusion/mptctl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptctl.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,1296 @@
+/*
+ *  linux/drivers/message/fusion/mptctl.c
+ *      Fusion MPT misc device (ioctl) driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      A big THANKS to Eddie C. Dost for fixing the ioctl path
+ *      and most importantly f/w download on sparc64 platform!
+ *      (plus Eddie's other helpful hints and insights)
+ *
+ *      Thanks to Arnaldo Carvalho de Melo for finding and patching
+ *      a potential memory leak in mpt_ioctl_do_fw_download(),
+ *      and for some kmalloc insight:-)
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston, Noah Romer
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptctl.c,v 1.23 2001/03/21 19:42:31 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/miscdevice.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/proc_fs.h>
+
+#define COPYRIGHT	"Copyright (c) 1999-2001 LSI Logic Corporation"
+#define MODULEAUTHOR	"Steven J. Ralston, Noah Romer"
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME		"Fusion MPT misc device (ioctl) driver"
+#define my_VERSION	MPT_LINUX_VERSION_COMMON
+#define MYNAM		"mptctl"
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static int mptctl_id = -1;
+static int rwperf_reset = 0;
+static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static int mpt_ioctl_rwperf(unsigned long arg);
+static int mpt_ioctl_rwperf_status(unsigned long arg);
+static int mpt_ioctl_rwperf_reset(unsigned long arg);
+static int mpt_ioctl_fw_download(unsigned long arg);
+static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
+static int mpt_ioctl_scsi_cmd(unsigned long arg);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Scatter gather list (SGL) sizes and limits...
+ */
+//#define MAX_SCSI_FRAGS	9
+#define MAX_FRAGS_SPILL1	9
+#define MAX_FRAGS_SPILL2	15
+#define FRAGS_PER_BUCKET	(MAX_FRAGS_SPILL2 + 1)
+
+//#define MAX_CHAIN_FRAGS	64
+//#define MAX_CHAIN_FRAGS	(15+15+15+16)
+#define MAX_CHAIN_FRAGS		(4 * MAX_FRAGS_SPILL2 + 1)
+
+//  Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
+//  Works out to: 592d bytes!     (9+1)*8 + 4*(15+1)*8
+//                  ^----------------- 80 + 512
+#define MAX_SGL_BYTES		((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
+
+/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
+#define MAX_KMALLOC_SZ		(128*1024)
+
+struct buflist {
+	u8	*kptr;
+	int	 len;
+};
+
+#define myMAX_TARGETS	(1<<4)
+#define myMAX_LUNS	(1<<3)
+#define myMAX_T_MASK	(myMAX_TARGETS-1)
+#define myMAX_L_MASK	(myMAX_LUNS-1)
+static u8  DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+
+static u32 fwReplyBuffer[16];
+static pMPIDefaultReply_t ReplyMsg = NULL;
+
+/* some private forw protos */
+static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags,
+		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma,
+		struct buflist *buflist, MPT_ADAPTER *ioc);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptctl_syscall_down - Down the MPT adapter syscall semaphore.
+ *	@ioc: Pointer to MPT adapter
+ *	@nonblock: boolean, non-zero if O_NONBLOCK is set
+ *
+ *	All of the mptctl commands can potentially sleep, which is illegal
+ *	with a spinlock held, thus we perform mutual exclusion here.
+ *
+ *	Returns negative errno on error, or zero for success.
+ */
+static inline int
+mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
+{
+	dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock));
+
+	if (nonblock) {
+		if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
+			return -EAGAIN;
+	} else {
+		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
+			return -ERESTARTSYS;
+	}
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  This is the callback for any message we have posted. The message itself
+ *  will be returned to the message pool when we return from the IRQ
+ *
+ *  This runs in irq context so be short and sweet.
+ */
+static int
+mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+{
+	u8 targ;
+
+	//dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n"));
+
+	if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+		targ = req->u.scsireq.TargetID & myMAX_T_MASK;
+		DevIosCount[targ][0]--;
+	} else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) {
+		// NOTE: Expects/requires non-Turbo reply!
+		dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n"));
+		memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
+		ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+	}
+
+	return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static loff_t
+mptctl_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static ssize_t
+mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n");
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static ssize_t
+mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  MPT ioctl handler
+ */
+static int
+mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct mpt_ioctl_sanity	*usanity = (struct mpt_ioctl_sanity *) arg;
+	struct mpt_ioctl_sanity	 ksanity;
+	int iocnum;
+	unsigned iocnumX;
+	int nonblock = (file->f_flags & O_NONBLOCK);
+	int ret;
+	MPT_ADAPTER *iocp = NULL;
+
+	dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n"));
+
+	if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) {
+		printk(KERN_ERR "%s::mpt_ioctl() @%d - "
+				"Unable to copy mpt_ioctl_sanity data @ %p\n",
+				__FILE__, __LINE__, (void*)usanity);
+		return -EFAULT;
+	}
+	ret = -ENXIO;				/* (-6) No such device or address */
+
+	/* Verify intended MPT adapter */
+	iocnumX = ksanity.iocnum & 0xFF;
+	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+	    (iocp == NULL)) {
+		printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX);
+		return -ENODEV;
+	}
+
+	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+		return ret;
+
+	dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name));
+
+	switch(cmd) {
+	case MPTRWPERF:
+		ret = mpt_ioctl_rwperf(arg);
+		break;
+	case MPTRWPERF_CHK:
+		ret = mpt_ioctl_rwperf_status(arg);
+		break;
+	case MPTRWPERF_RESET:
+		ret = mpt_ioctl_rwperf_reset(arg);
+		break;
+	case MPTFWDOWNLOAD:
+		ret = mpt_ioctl_fw_download(arg);
+		break;
+	case MPTSCSICMD:
+		ret = mpt_ioctl_scsi_cmd(arg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+	return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int mptctl_open(struct inode *inode, struct file *file)
+{
+	/*
+	 * Should support multiple management users
+	 */
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int mptctl_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_fw_download(unsigned long arg)
+{
+	struct mpt_fw_xfer	*ufwdl = (struct mpt_fw_xfer *) arg;
+	struct mpt_fw_xfer	 kfwdl;
+
+	dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
+	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
+		printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+				"Unable to copy mpt_fw_xfer struct @ %p\n",
+				__FILE__, __LINE__, (void*)ufwdl);
+		return -EFAULT;
+	}
+
+	return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT FW Download
+ */
+static int
+mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
+{
+	FWDownload_t		*dlmsg;
+	MPT_FRAME_HDR		*mf;
+	MPT_ADAPTER		*iocp;
+//	char			*fwbuf;
+//	dma_addr_t		 fwbuf_dma;
+	FWDownloadTCSGE_t	*fwVoodoo;
+//	SGEAllUnion_t		*fwSgl;
+	int			 ret;
+
+	SGESimple32_t	*sgl;
+	SGESimple32_t	*sgOut, *sgIn;
+	dma_addr_t	 sgl_dma;
+	struct buflist	*buflist;
+	struct buflist	*bl;
+	int		 numfrags = 0;
+	int		 maxfrags;
+	int		 n = 0;
+	u32		 sgdir;
+	u32		 nib;
+	int		 fw_bytes_copied = 0;
+	u16		 iocstat;
+	int		 i;
+
+	dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
+
+	dprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));
+	dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
+	dprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
+
+	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
+		printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+				__FILE__, __LINE__, ioc);
+		return -ENXIO; /* (-6) No such device or address */
+	}
+
+	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
+		return -EAGAIN;
+	dlmsg = (FWDownload_t*) mf;
+	fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL;
+	sgOut = (SGESimple32_t *) (fwVoodoo + 1);
+
+	/*
+	 * Construct f/w download request
+	 */
+	dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
+	dlmsg->Reserved = 0;
+	dlmsg->ChainOffset = 0;
+	dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
+	dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
+	dlmsg->MsgFlags = 0;
+
+	fwVoodoo->Reserved = 0;
+	fwVoodoo->ContextSize = 0;
+	fwVoodoo->DetailsLength = 12;
+	fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+	fwVoodoo->Reserved1 = 0;
+	fwVoodoo->ImageOffset = 0;
+	fwVoodoo->ImageSize = cpu_to_le32(fwlen);
+
+	/*
+	 * Need to kmalloc area(s) for holding firmware image bytes.
+	 * But we need to do it piece meal, using a proper
+	 * scatter gather list (with 128kB MAX hunks).
+	 * 
+	 * A practical limit here might be # of sg hunks that fit into
+	 * a single IOC request frame; 12 or 8 (see below), so:
+	 * For FC9xx: 12 x 128kB == 1.5 mB (max)
+	 * For C1030:  8 x 128kB == 1   mB (max)
+	 * We could support chaining, but things get ugly(ier:)
+	 */
+	sgdir = 0x04000000;		/* IOC will READ from sys mem */
+	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+		return -ENOMEM;
+
+	/*
+	 * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
+	 * for FC9xx f/w image, but calculate max number of sge hunks
+	 * we can fit into a request frame, and limit ourselves to that.
+	 * (currently no chain support)
+	 * For FC9xx: (128-12-16)/8 = 12.5 = 12
+	 * For C1030:  (96-12-16)/8 =  8.5 =  8
+	 */
+	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t);
+	if (numfrags > maxfrags) {
+		ret = -EMLINK;
+		goto fwdl_out;
+	}
+
+	dprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
+
+	/*
+	 * Parse SG list, copying sgl itself,
+	 * plus f/w image hunks from user space as we go...
+	 */
+	ret = -EFAULT;
+	sgIn = sgl;
+	bl = buflist;
+	for (i=0; i < numfrags; i++) {
+		nib = (sgIn->FlagsLength & 0xF0000000) >> 28;
+		/* skip ignore/chain. */
+		if (nib == 0 || nib == 3) {
+			;
+		} else if (sgIn->Address) {
+			*sgOut = *sgIn;
+			n++;
+			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
+				printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+						"Unable to copy f/w buffer hunk#%d @ %p\n",
+						__FILE__, __LINE__, n, (void*)ufwbuf);
+				goto fwdl_out;
+			}
+			fw_bytes_copied += bl->len;
+		}
+		sgIn++;
+		bl++;
+		sgOut++;
+	}
+
+#ifdef MPT_DEBUG
+	{
+		u32 *m = (u32 *)mf;
+		printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
+		for (i=0; i < 7+numfrags*2; i++)
+			printk(" %08x", le32_to_cpu(m[i]));
+		printk("\n");
+	}
+#endif
+
+	/*
+	 * Finally, perform firmware download.
+	 */
+	ReplyMsg = NULL;
+	mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+	/*
+	 *  Wait until the reply has been received
+	 */
+	{
+		int	 foo = 0;
+
+		while (ReplyMsg == NULL) {
+			if (!(foo%1000000)) {
+				dprintk((KERN_INFO "DbG::_do_fwdl: "
+					   "In ReplyMsg loop - iteration %d\n",
+					   foo)); //tc
+			}
+			ret = -ETIME;
+			if (++foo > 60000000)
+				goto fwdl_out;
+			mb();
+			schedule();
+			barrier();
+		}
+	}
+
+	if (sgl)
+        	kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
+	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
+		printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
+		return 0;
+	} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
+		printk(KERN_WARNING MYNAM ": ?Hmmm...  %s says it doesn't support F/W download!?!\n",
+				iocp->name);
+		printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
+		return -EBADRQC;
+	} else if (iocstat == MPI_IOCSTATUS_BUSY) {
+		printk(KERN_WARNING MYNAM ": Warning!  %s says: IOC_BUSY!\n", iocp->name);
+		printk(KERN_WARNING MYNAM ": (try again later?)\n");
+		return -EBUSY;
+	} else {
+		printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR!  %s returned [bad] status = %04xh\n",
+				    iocp->name, iocstat);
+		printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
+		return -ENOMSG;
+	}
+	return 0;
+
+fwdl_out:
+        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+	return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  NEW rwperf (read/write performance) stuff starts here...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static SGESimple32_t *
+kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
+		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
+{
+	SGESimple32_t	*sglbuf = NULL;
+	struct buflist	*buflist = NULL;
+	int		 numfrags = 0;
+	int		 fragcnt = 0;
+	int		 alloc_sz = MIN(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
+	int		 bytes_allocd = 0;
+	int		 this_alloc;
+	SGESimple32_t	*sgl;
+	u32		 pa;					// phys addr
+	SGEChain32_t	*last_chain = NULL;
+	SGEChain32_t	*old_chain = NULL;
+	int		 chaincnt = 0;
+	int		 i, buflist_ent;
+	int		 sg_spill = MAX_FRAGS_SPILL1;
+	int		 dir;
+
+	*frags = 0;
+	*blp = NULL;
+	i = MAX_SGL_BYTES / 8;
+	buflist = kmalloc(i, GFP_USER);
+	if (buflist == NULL)
+		return NULL;
+	memset(buflist, 0, i);
+	buflist_ent = 0;
+
+	sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
+	if (sglbuf == NULL)
+		goto free_and_fail;
+
+	if (sgdir & 0x04000000)
+		dir = PCI_DMA_TODEVICE;
+	else
+		dir = PCI_DMA_FROMDEVICE;
+
+	sgl = sglbuf;
+	while (bytes_allocd < bytes) {
+		this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
+		buflist[buflist_ent].len = this_alloc;
+		buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
+								 this_alloc,
+								 &pa);
+		if (buflist[buflist_ent].kptr == NULL) {
+			alloc_sz = alloc_sz / 2;
+			if (alloc_sz == 0) {
+				printk(KERN_WARNING MYNAM "-SG: No can do - "
+						    "not enough memory!   :-(\n");
+				printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
+						    numfrags);
+				goto free_and_fail;
+			}
+			continue;
+		} else {
+			dma_addr_t dma_addr;
+
+			bytes_allocd += this_alloc;
+
+			/* Write one SIMPLE sge */
+			sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
+			dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+			sgl->Address = cpu_to_le32(dma_addr);
+
+			fragcnt++;
+			numfrags++;
+			sgl++;
+			buflist_ent++;
+		}
+
+		if (bytes_allocd >= bytes)
+			break;
+
+		/* Need to chain? */
+		if (fragcnt == sg_spill) {
+			dma_addr_t chain_link;
+
+			if (last_chain != NULL)
+				last_chain->NextChainOffset = 0x1E;
+
+			fragcnt = 0;
+			sg_spill = MAX_FRAGS_SPILL2;
+
+			/* fixup previous SIMPLE sge */
+			sgl[-1].FlagsLength |= cpu_to_le32(0x80000000);
+
+			chain_link = (*sglbuf_dma) +
+				((u8 *)(sgl+1) - (u8 *)sglbuf);
+
+			/* Write one CHAIN sge */
+			sgl->FlagsLength = cpu_to_le32(0x30000080);
+			sgl->Address = cpu_to_le32(chain_link);
+
+			old_chain = last_chain;
+			last_chain = (SGEChain32_t*)sgl;
+			chaincnt++;
+			numfrags++;
+			sgl++;
+		}
+
+		/* overflow check... */
+		if (numfrags*8 > MAX_SGL_BYTES) {
+			/* GRRRRR... */
+			printk(KERN_WARNING MYNAM "-SG: No can do - "
+					    "too many SG frags!   :-(\n");
+			printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
+					    numfrags);
+			goto free_and_fail;
+		}
+	}
+
+	/* Last sge fixup: set LE+eol+eob bits */
+	sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000);
+
+	/* Chain fixup needed? */
+	if (last_chain != NULL && fragcnt < 16)
+		last_chain->Length = cpu_to_le16(fragcnt * 8);
+
+	*frags = numfrags;
+	*blp = buflist;
+
+	dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+			   "%d SG frags generated!  (%d CHAIN%s)\n",
+			   numfrags, chaincnt, chaincnt>1?"s":""));
+
+	dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+			   "last (big) alloc_sz=%d\n",
+			   alloc_sz));
+
+	return sglbuf;
+
+free_and_fail:
+	if (sglbuf != NULL) {
+		int i;
+
+		for (i = 0; i < numfrags; i++) {
+			dma_addr_t dma_addr;
+			u8 *kptr;
+			int len;
+
+			if ((sglbuf[i].FlagsLength >> 24) == 0x30)
+				continue;
+
+			dma_addr = le32_to_cpu(sglbuf[i].Address);
+			kptr = buflist[i].kptr;
+			len = buflist[i].len;
+
+			pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+		}
+		pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
+	}
+	kfree(buflist);
+	return NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
+{
+	SGESimple32_t	*sg = sgl;
+	struct buflist	*bl = buflist;
+	u32		 nib;
+	int		 dir;
+	int		 n = 0;
+
+	if (sg->FlagsLength & 0x04000000)
+		dir = PCI_DMA_TODEVICE;
+	else
+		dir = PCI_DMA_FROMDEVICE;
+
+	nib = (sg->FlagsLength & 0xF0000000) >> 28;
+	while (! (nib & 0x4)) { /* eob */
+		/* skip ignore/chain. */
+		if (nib == 0 || nib == 3) {
+			;
+		} else if (sg->Address) {
+			dma_addr_t dma_addr;
+			void *kptr;
+			int len;
+
+			dma_addr = le32_to_cpu(sg->Address);
+			kptr = bl->kptr;
+			len = bl->len;
+			pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
+			pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+			n++;
+		}
+		sg++;
+		bl++;
+		nib = (sg->FlagsLength & 0xF0000000) >> 28;
+	}
+
+	/* we're at eob! */
+	if (sg->Address) {
+		dma_addr_t dma_addr;
+		void *kptr;
+		int len;
+
+		dma_addr = le32_to_cpu(sg->Address);
+		kptr = bl->kptr;
+		len = bl->len;
+		pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
+		pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+		n++;
+	}
+
+	pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
+	kfree(buflist);
+	dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src,
+		      char *caller, MPT_ADAPTER **iocpp)
+{
+	char	*myname = "_rwperf_init()";
+	int	 ioc;
+
+	/* get copy of structure passed from user space */
+	if (copy_from_user(dest, (void*)src, sizeof(*dest))) {
+		printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n",
+				myname, __LINE__, (void*)src);
+		return -EFAULT;				/* (-14) Bad address */
+	} else {
+		dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}"
+				   ": %d %d %d %d %d\n",
+				   dest->iocnum, dest->target,
+				   (int)dest->qdepth, dest->iters, dest->nblks ));
+		dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}"
+				   ": %d %d %d %d %d\n",
+				   dest->cache_sz, dest->skip, dest->range,
+				   dest->rdwr, dest->seqran ));
+
+		/* Get the MPT adapter id. */
+		if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) {
+			printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n",
+					myname, __LINE__, dest->iocnum);
+			return -ENXIO;			/* (-6) No such device or address */
+		} else {
+			dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n",
+					caller, dest->iocnum, dest->target));
+		}
+	}
+
+	return ioc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*  Treat first N blocks of disk as sacred!  */
+#define SACRED_BLOCKS	100
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf(unsigned long arg)
+{
+	struct mpt_raw_r_w	 kPerfInfo;
+				/* NOTE: local copy, on stack==KERNEL_SPACE! */
+	u8		 target, targetM;
+	u8		 lun, lunM;
+	u8		 scsiop;
+	int		 qdepth;
+	int		 iters;
+	int		 cache_sz;
+	u32		 xferbytes;
+	u32		 scsidir;
+	u32		 qtag;
+	u32		 scsictl;
+	u32		 sgdir;
+	u32		 blkno;
+	u32		 sbphys;
+	SGESimple32_t	*sgl;
+	dma_addr_t	 sgl_dma;
+	struct buflist	*buflist;
+	SGESimple32_t	*sgOut, *sgIn;
+	int		 numfrags;
+	u32		*msg;
+	int		 i;
+	int		 ioc;
+	MPT_FRAME_HDR	*mf;
+	MPT_ADAPTER	*iocp;
+	int		 sgfragcpycnt;
+	int		 blklo, blkhi;
+	u8		 nextchainoffset;
+	u8		*SenseBuf;
+	dma_addr_t	 SenseBufDMA;
+	char		*myname = "_rwperf()";
+
+    dprintk((KERN_INFO "%s - starting...\n", myname));
+
+    /* Validate target device */
+    if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+        return ioc;
+
+    /* Allocate DMA'able memory for the sense buffer. */
+    SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA);
+
+    /* set perf parameters from input */
+    target = kPerfInfo.target & 0x0FF;
+    targetM = target & myMAX_T_MASK;
+    lun = kPerfInfo.lun & 0x1F;			// LUN=31 max
+    lunM = lun & myMAX_L_MASK;
+    qdepth = kPerfInfo.qdepth;
+    iters = kPerfInfo.iters;
+    xferbytes = ((u32)kPerfInfo.nblks)<<9;
+
+    DevInUse[targetM][lunM] = 1;
+    DevIosCount[targetM][lunM] = 0;
+
+    cache_sz = kPerfInfo.cache_sz * 1024;	// CacheSz in kB!
+
+    /* ToDo: */
+    /* get capacity (?) */
+
+
+    // pre-build, one time, everything we can for speed in the loops below...
+
+    scsiop = 0x28;				// default to SCSI READ!
+    scsidir = MPI_SCSIIO_CONTROL_READ;		// DATA IN  (host<--ioc<--dev)
+						// 02000000
+    qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;		// 00000000
+
+    if (xferbytes == 0) {
+        // Do 0-byte READ!!!
+        //  IMPORTANT!  Need to set no SCSI DIR for this!
+        scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+    }
+
+    scsictl = scsidir | qtag;
+
+    /*
+     *  Set sgdir for DMA transfer.
+     */
+//    sgdir   = 0x04000000;		// SCSI WRITE
+    sgdir = 0x00000000;			// SCSI READ
+
+    if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+        return -ENOMEM;
+
+    sgfragcpycnt = MIN(10,numfrags);
+    nextchainoffset = 0;
+    if (numfrags > 10)
+        nextchainoffset = 0x1E;
+
+    sbphys = SenseBufDMA;
+
+    rwperf_reset = 0;
+
+//    do {	// target-loop
+
+        blkno = SACRED_BLOCKS;		// Treat first N blocks as sacred!
+					// FIXME!  Skip option
+        blklo = blkno;
+        blkhi = blkno;
+
+        do {    // inner-loop
+
+            while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+                mb();
+                schedule();
+                barrier();
+            }
+            msg = (u32*)mf;
+
+            /* Start piecing the SCSIIORequest together */
+            msg[0] = 0x00000000 | nextchainoffset<<16 | target;
+            msg[1] = 0x0000FF0A;				// 255 sense bytes, 10-byte CDB!
+            msg[3] = lun << 8;
+            msg[4] = 0;
+            msg[5] = scsictl;
+
+            // 16 bytes of CDB @ msg[6,7,8,9] are below...
+
+            msg[6] = (   ((blkno & 0xFF000000) >> 8)
+                       | ((blkno & 0x00FF0000) << 8)
+                       | scsiop );
+            msg[7] = (   (((u32)kPerfInfo.nblks & 0x0000FF00) << 16)
+                       | ((blkno & 0x000000FF) << 8)
+                       | ((blkno & 0x0000FF00) >> 8) );
+            msg[8] = (kPerfInfo.nblks & 0x00FF);
+            msg[9] = 0;
+
+            msg[10] = xferbytes;
+
+//            msg[11] = 0xD0000100;
+//            msg[12] = sbphys;
+//            msg[13] = 0;
+            msg[11] = sbphys;
+
+            // Copy the SGL...
+            if (xferbytes) {
+                sgOut = (SGESimple32_t*)&msg[12];
+                sgIn  = sgl;
+                for (i=0; i < sgfragcpycnt; i++)
+                    *sgOut++ = *sgIn++;
+            }
+
+            // fubar!  QueueDepth issue!!!
+            while (    !rwperf_reset
+                    && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) )
+            {
+                mb();
+                schedule();
+                barrier();
+            }
+
+//            blkno += kPerfInfo.nblks;
+// EXP Stuff!
+// Try optimizing to certain cache size for the target!
+// by keeping blkno within cache range if at all possible
+#if 0
+            if (    cache_sz
+                 && ((2 * kPerfInfo.nblks) <= (cache_sz>>9))
+                 && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
+                blkno = SACRED_BLOCKS;
+            else
+                blkno += kPerfInfo.nblks;
+#endif
+// Ok, cheat!
+            if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
+                   blkno = SACRED_BLOCKS;
+            else
+                blkno += kPerfInfo.nblks;
+
+            if (blkno > blkhi)
+                blkhi = blkno;
+
+            DevIosCount[targetM][lunM]++;
+
+            /*
+             *  Finally, post the request
+             */
+            mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+
+            /* let linux breath! */
+            mb();
+            schedule();
+            barrier();
+
+            //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters));
+
+        } while ((--iters > 0) && !rwperf_reset);
+
+        dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi));
+        dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target));
+
+//        //  TEMPORARY!
+//        target = 0;
+
+//    } while (target);
+
+
+    if (DevIosCount[targetM][lunM]) {
+        dprintk((KERN_INFO "  DbG: DevIosCount[%d][%d]=%d\n",
+                targetM, lunM, DevIosCount[targetM][lunM]));
+    }
+
+    while (DevIosCount[targetM][lunM]) {
+        //dprintk((KERN_DEBUG "  DbG: Waiting... DevIosCount[%d][%d]=%d\n",
+        //        targetM, lunM, DevIosCount[targetM][lunM]));
+        mb();
+        schedule();
+        barrier();
+    }
+    DevInUse[targetM][lunM] = 0;
+
+    pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA);
+
+    if (sgl)
+        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+    dprintk((KERN_INFO "  *** done ***\n"));
+
+    return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_status(unsigned long arg)
+{
+	struct mpt_raw_r_w	 kPerfInfo;
+				/* NOTE: local copy, on stack==KERNEL_SPACE! */
+	MPT_ADAPTER	*iocp;
+	int		 ioc;
+//	u8		 targ;
+//	u8		 lun;
+	int		 T, L;
+	char		*myname = "_rwperf_status()";
+
+
+	dprintk((KERN_INFO "%s - starting...\n", myname));
+
+	/* Get a pointer to the MPT adapter. */
+	if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+		return ioc;
+
+	/* set perf parameters from input */
+//	targ = kPerfInfo.target & 0xFF;
+//	lun = kPerfInfo.lun & 0x1F;
+
+	for (T=0; T < myMAX_TARGETS; T++)
+		for (L=0; L < myMAX_LUNS; L++)
+			if (DevIosCount[T][L]) {
+				printk(KERN_INFO "%s: ioc%d->00:%02x:%02x"
+						 ", IosCnt=%d\n",
+						 myname, ioc, T, L, DevIosCount[T][L] );
+			}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_reset(unsigned long arg)
+{
+	struct mpt_raw_r_w	 kPerfInfo;
+				/* NOTE: local copy, on stack==KERNEL_SPACE! */
+	MPT_ADAPTER	*iocp;
+	int		 ioc;
+//	u8		 targ;
+//	u8		 lun;
+	int		 T, L;
+	int		 i;
+	char		*myname = "_rwperf_reset()";
+
+	dprintk((KERN_INFO "%s - starting...\n", myname));
+
+	/* Get MPT adapter id. */
+	if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+		return ioc;
+
+	/* set perf parameters from input */
+//	targ = kPerfInfo.target & 0xFF;
+//	lun = kPerfInfo.lun & 0x1F;
+
+	rwperf_reset = 1;
+	for (i=0; i < 1000000; i++) {
+		mb();
+		schedule();
+		barrier();
+	}
+	rwperf_reset = 0;
+
+	for (T=0; T < myMAX_TARGETS; T++)
+		for (L=0; L < myMAX_LUNS; L++)
+			if (DevIosCount[T][L]) {
+				printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, "
+						 "IosCnt RESET! (from %d to 0)\n",
+						 myname, ioc, T, L, DevIosCount[T][L] );
+				DevIosCount[T][L] = 0;
+				DevInUse[T][L] = 0;
+			}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_scsi_cmd(unsigned long arg)
+{
+	return -ENOSYS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static struct file_operations mptctl_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
+	owner:		THIS_MODULE,
+#endif
+	llseek:		mptctl_llseek,
+	read:		mptctl_read,
+	write:		mptctl_write,
+	ioctl:		mpt_ioctl,
+	open:		mptctl_open,
+	release:	mptctl_release,
+};
+
+static struct miscdevice mptctl_miscdev = {
+	MPT_MINOR,
+	MYNAM,
+	&mptctl_fops
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+
+/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
+extern int register_ioctl32_conversion(unsigned int cmd,
+				       int (*handler)(unsigned int,
+						      unsigned int,
+						      unsigned long,
+						      struct file *));
+int unregister_ioctl32_conversion(unsigned int cmd);
+
+struct mpt_fw_xfer32 {
+	unsigned int iocnum;
+	unsigned int fwlen;
+	u32 bufp;
+};
+
+#define MPTFWDOWNLOAD32     _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+			unsigned long arg, struct file *filp)
+{
+	struct mpt_fw_xfer32 kfw32;
+	struct mpt_fw_xfer kfw;
+	MPT_ADAPTER *iocp = NULL;
+	int iocnum, iocnumX;
+	int nonblock = (filp->f_flags & O_NONBLOCK);
+	int ret;
+
+	dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+
+	if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
+		return -EFAULT;
+
+	/* Verify intended MPT adapter */
+	iocnumX = kfw32.iocnum & 0xFF;
+	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+	    (iocp == NULL)) {
+		printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+				__LINE__, iocnumX);
+		return -ENODEV;
+	}
+
+	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+		return ret;
+
+	kfw.iocnum = iocnum;
+	kfw.fwlen = kfw32.fwlen;
+	kfw.bufp = (void *)(unsigned long)kfw32.bufp;
+
+	ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+
+	up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+	return ret;
+}
+
+#if 0		/* { */
+static int
+sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+			unsigned long arg, struct file *filp)
+{
+	struct mpt_fw_xfer32 kfw32;
+	struct mpt_fw_xfer kfw;
+	mm_segment_t old_fs;
+	int ret;
+
+	dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+
+	if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
+		return -EFAULT;
+
+	/* Verify intended MPT adapter */
+	iocnumX = kfw32.iocnum & 0xFF;
+	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+	    (iocp == NULL)) {
+		printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+				__LINE__, iocnumX);
+		return -ENODEV;
+	}
+
+	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+		return ret;
+
+	kfw.iocnum = iocnum;
+	kfw.fwlen = kfw32.fwlen;
+	kfw.bufp = (void *)(unsigned long)kfw32.bufp;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, MPTFWDOWNLOAD, (unsigned long)&kfw);
+	set_fs(old_fs);
+
+	up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+	return ret;
+}
+#endif		/* #if 0 } */
+
+#endif		/*} linux >= 2.3.x */
+#endif		/*} sparc */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init mptctl_init(void)
+{
+	int err;
+	int i;
+	int where = 1;
+
+	show_mptmod_ver(my_NAME, my_VERSION);
+
+	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+		sema_init(&mptctl_syscall_sem_ioc[i], 1);
+	}
+
+#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
+	err = register_ioctl32_conversion(MPTRWPERF, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
+					  sparc32_mptfwxfer_ioctl);
+	if (++where && err) goto out_fail;
+#endif		/*} linux >= 2.3.x */
+#endif		/*} sparc */
+
+	if (misc_register(&mptctl_miscdev) == -1) {
+		printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
+		err = -EBUSY;
+		goto out_fail;
+	}
+	printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
+	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
+
+	/*
+	 *  Install our handler
+	 */
+	++where;
+	if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
+		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
+		misc_deregister(&mptctl_miscdev);
+		err = -EBUSY;
+		goto out_fail;
+	}
+
+	return 0;
+
+out_fail:
+
+#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
+	printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
+			" (%d:err=%d)\n", where, err);
+	unregister_ioctl32_conversion(MPTRWPERF);
+	unregister_ioctl32_conversion(MPTRWPERF_CHK);
+	unregister_ioctl32_conversion(MPTRWPERF_RESET);
+	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
+#endif		/*} linux >= 2.3.x */
+#endif		/*} sparc */
+
+	return err;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void mptctl_exit(void)
+{
+	misc_deregister(&mptctl_miscdev);
+	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
+	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
+
+	mpt_deregister(mptctl_id);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(mptctl_init);
+module_exit(mptctl_exit);
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptlan.c linux/drivers/message/fusion/mptlan.c
--- v2.4.6/linux/drivers/message/fusion/mptlan.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptlan.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,1462 @@
+/*
+ *  linux/drivers/message/fusion/mptlan.c
+ *      IP Over Fibre Channel device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      Special thanks goes to the I2O LAN driver people at the
+ *      University of Helsinki, who, unbeknownst to them, provided
+ *      the inspiration and initial structure for this driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      A really huge debt of gratitude is owed to Eddie C. Dost
+ *      for gobs of hard work fixing and optimizing LAN code.
+ *      THANK YOU!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 2000-2001 LSI Logic Corporation
+ *  Originally By: Noah Romer
+ *
+ *  $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Define statements used for debugging
+ */
+//#define MPT_LAN_IO_DEBUG
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "mptlan.h"
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#define MYNAM		"mptlan"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT LAN message sizes without variable part.
+ */
+#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \
+	(sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION))
+
+#define MPT_LAN_TRANSACTION32_SIZE \
+	(sizeof(SGETransaction32_t) - sizeof(u32))
+
+/*
+ *  Fusion MPT LAN private structures
+ */
+
+struct BufferControl {
+	struct sk_buff	*skb;
+	dma_addr_t	dma;
+	unsigned int	len;
+};
+
+struct mpt_lan_priv {
+	MPT_ADAPTER *mpt_dev;
+	u8 pnum; /* Port number in the IOC. This is not a Unix network port! */
+
+	atomic_t buckets_out;	  	/* number of unused buckets on IOC */
+	int bucketthresh;		/* Send more when this many used */
+
+	int *mpt_txfidx; /* Free Tx Context list */
+	int mpt_txfidx_tail;
+	spinlock_t txfidx_lock;
+
+	int *mpt_rxfidx; /* Free Rx Context list */
+	int mpt_rxfidx_tail;
+	spinlock_t rxfidx_lock;
+
+	struct BufferControl *RcvCtl;	/* Receive BufferControl structs */
+	struct BufferControl *SendCtl;	/* Send BufferControl structs */
+
+	int max_buckets_out;	   	/* Max buckets to send to IOC */
+	int tx_max_out;		   	/* IOC's Tx queue len */
+
+	u32 total_posted;
+	u32 total_received;
+	struct net_device_stats stats;	/* Per device statistics */
+
+	struct tq_struct post_buckets_task;
+	unsigned long post_buckets_active;
+};
+
+struct mpt_lan_ohdr {
+	u16	dtype;
+	u8	daddr[FC_ALEN];
+	u16	stype;
+	u8	saddr[FC_ALEN];
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Forward protos...
+ */
+static int  lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
+		       MPT_FRAME_HDR *reply);
+static int  mpt_lan_open(struct net_device *dev);
+static int  mpt_lan_reset(struct net_device *dev);
+static int  mpt_lan_close(struct net_device *dev);
+static void mpt_lan_post_receive_buckets(void *dev_id);
+static void mpt_lan_wake_post_buckets_task(struct net_device *dev);
+static int  mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
+static int  mpt_lan_receive_post_reply(struct net_device *dev,
+				       LANReceivePostReply_t *pRecvRep);
+static int  mpt_lan_send_turbo(struct net_device *dev, u32 tmsg);
+static int  mpt_lan_send_reply(struct net_device *dev,
+			       LANSendReply_t *pSendRep);
+static int  mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
+					 struct net_device *dev);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Fusion MPT LAN private data
+ */
+static int LanCtx = -1;
+
+static u32 max_buckets_out = 127;
+static u32 tx_max_out_p = 127 - 16;
+
+static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN external data
+ */
+extern int mpt_lan_index;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	lan_reply - Handle all data sent from the hardware.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mf: Pointer to original MPT request frame (NULL if TurboReply)
+ *	@reply: Pointer to MPT reply frame
+ *
+ *	Returns 1 indicating original alloc'd request frame ptr
+ *	should be freed, or 0 if it shouldn't.
+ */
+static int
+lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+	struct net_device *dev = mpt_landev[ioc->id];
+	int FreeReqFrame = 0;
+
+	dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n",
+		  IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+//	dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n",
+//			mf, reply));
+
+	if (mf == NULL) {
+		u32 tmsg = CAST_PTR_TO_U32(reply);
+
+		dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n",
+				IOC_AND_NETDEV_NAMES_s_s(dev),
+				tmsg));
+
+		switch (GET_LAN_FORM(tmsg)) {
+
+		// NOTE!  (Optimization) First case here is now caught in
+		//  mptbase.c::mpt_interrupt() routine and callcack here
+		//  is now skipped for this case!  20001218 -sralston
+#if 0
+		case LAN_REPLY_FORM_MESSAGE_CONTEXT:
+//			dioprintk((KERN_INFO MYNAM "/lan_reply: "
+//				  "MessageContext turbo reply received\n"));
+			FreeReqFrame = 1;
+			break;
+#endif
+
+		case LAN_REPLY_FORM_SEND_SINGLE:
+//			dioprintk((MYNAM "/lan_reply: "
+//				  "calling mpt_lan_send_reply (turbo)\n"));
+  
+			// Potential BUG here?  -sralston
+			//	FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
+			//  If/when mpt_lan_send_turbo would return 1 here,
+			//  calling routine (mptbase.c|mpt_interrupt)
+			//  would Oops because mf has already been set
+			//  to NULL.  So after return from this func,
+			//  mpt_interrupt() will attempt to put (NULL) mf ptr
+			//  item back onto it's adapter FreeQ - Oops!:-(
+			//  It's Ok, since mpt_lan_send_turbo() *currently*
+			//  always returns 0, but..., just in case:
+
+			(void) mpt_lan_send_turbo(dev, tmsg);
+			FreeReqFrame = 0;
+
+			break;
+
+		case LAN_REPLY_FORM_RECEIVE_SINGLE:
+//			dioprintk((KERN_INFO MYNAM "@lan_reply: "
+//				  "rcv-Turbo = %08x\n", tmsg));
+			mpt_lan_receive_post_turbo(dev, tmsg);
+			break;
+
+		default:
+			printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply "
+				"that I don't know what to do with\n");
+
+			/* CHECKME!  Hmmm...  FreeReqFrame is 0 here; is that right? */
+
+			break;
+		}
+
+		return FreeReqFrame;
+	}
+
+//	msg = (u32 *) reply;
+//	dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n",
+//		  le32_to_cpu(msg[0]), le32_to_cpu(msg[1]),
+//		  le32_to_cpu(msg[2]), le32_to_cpu(msg[3])));
+//	dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n",
+//		  reply->u.hdr.Function));
+
+	switch (reply->u.hdr.Function) {
+
+	case MPI_FUNCTION_LAN_SEND:
+	{
+		LANSendReply_t *pSendRep;
+
+		pSendRep = (LANSendReply_t *) reply;
+		FreeReqFrame = mpt_lan_send_reply(dev, pSendRep);
+		break;
+	}
+
+	case MPI_FUNCTION_LAN_RECEIVE:
+	{
+		LANReceivePostReply_t *pRecvRep;
+
+		pRecvRep = (LANReceivePostReply_t *) reply;
+		if (pRecvRep->NumberOfContexts) {
+			mpt_lan_receive_post_reply(dev, pRecvRep);
+			if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+				FreeReqFrame = 1;
+		} else
+			dioprintk((KERN_INFO MYNAM "@lan_reply: zero context "
+				  "ReceivePostReply received.\n"));
+		break;
+	}
+
+	case MPI_FUNCTION_LAN_RESET:
+		/* Just a default reply. Might want to check it to
+		 * make sure that everything went ok.
+		 */
+		FreeReqFrame = 1;
+		break;
+
+	case MPI_FUNCTION_EVENT_NOTIFICATION:
+	case MPI_FUNCTION_EVENT_ACK:
+		/* UPDATE!  20010120 -sralston
+		 *  _EVENT_NOTIFICATION should NOT come down this path any more.
+		 *  Should be routed to mpt_lan_event_process(), but just in case...
+		 */
+		FreeReqFrame = 1;
+		break;
+
+	default:
+		printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo "
+			"reply that I don't know what to do with\n");
+
+		/* CHECKME!  Hmmm...  FreeReqFrame is 0 here; is that right? */
+		FreeReqFrame = 1;
+
+		break;
+	}
+
+	return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+	dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
+
+	switch (le32_to_cpu(pEvReply->Event)) {
+	case MPI_EVENT_NONE:				/* 00 */
+	case MPI_EVENT_LOG_DATA:			/* 01 */
+	case MPI_EVENT_STATE_CHANGE:			/* 02 */
+	case MPI_EVENT_UNIT_ATTENTION:			/* 03 */
+	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
+	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
+	case MPI_EVENT_RESCAN:				/* 06 */
+		/* Ok, do we need to do anything here? As far as
+		   I can tell, this is when a new device gets added
+		   to the loop. */
+	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
+	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
+	case MPI_EVENT_LOGOUT:				/* 09 */
+	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
+	default:
+		break;
+	}
+
+	/*
+	 *  NOTE: pEvent->AckRequired handling now done in mptbase.c;
+	 *  Do NOT do it here now!
+	 */
+
+	return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_open(struct net_device *dev)
+{
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	int i;
+
+	mpt_lan_reset(dev);
+
+	priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL);
+	if (priv->mpt_txfidx == NULL)
+		goto out;
+	priv->mpt_txfidx_tail = -1;
+
+	priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+				GFP_KERNEL);
+	if (priv->SendCtl == NULL)
+		goto out_mpt_txfidx;
+	for (i = 0; i < priv->tx_max_out; i++) {
+		memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+		priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
+	}
+
+	dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
+
+	priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
+				   GFP_KERNEL);
+	if (priv->mpt_rxfidx == NULL)
+		goto out_SendCtl;
+	priv->mpt_rxfidx_tail = -1;
+
+	priv->RcvCtl = kmalloc(priv->max_buckets_out *
+						sizeof(struct BufferControl),
+			       GFP_KERNEL);
+	if (priv->RcvCtl == NULL)
+		goto out_mpt_rxfidx;
+	for (i = 0; i < priv->max_buckets_out; i++) {
+		memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
+	}
+
+/**/	dprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
+/**/	for (i = 0; i < priv->tx_max_out; i++)
+/**/		dprintk((" %xh", priv->mpt_txfidx[i]));
+/**/	dprintk(("\n"));
+
+	dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+
+	mpt_lan_post_receive_buckets(dev);
+	printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev));
+
+	if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) {
+		/* FIXME! */
+	}
+
+	netif_start_queue(dev);
+	dprintk((KERN_INFO MYNAM "/lo: Done.\n"));
+
+	return 0;
+out_mpt_rxfidx:
+	kfree(priv->mpt_rxfidx);
+	priv->mpt_rxfidx = NULL;
+out_SendCtl:
+	kfree(priv->SendCtl);
+	priv->SendCtl = NULL;
+out_mpt_txfidx:
+	kfree(priv->mpt_txfidx);
+	priv->mpt_txfidx = NULL;
+out:	return -ENOMEM;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_reset(struct net_device *dev)
+{
+	MPT_FRAME_HDR *mf;
+	LANResetRequest_t *pResetReq;
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+	mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
+
+	if (mf == NULL) {
+/*		dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
+		"Unable to allocate a request frame.\n"));
+*/
+		return -1;
+	}
+
+	pResetReq = (LANResetRequest_t *) mf;
+
+	pResetReq->Function	= MPI_FUNCTION_LAN_RESET;
+	pResetReq->ChainOffset	= 0;
+	pResetReq->Reserved	= 0;
+	pResetReq->PortNumber	= priv->pnum;
+	pResetReq->MsgFlags	= 0;
+	pResetReq->Reserved2	= 0;
+
+	mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf);
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_close(struct net_device *dev)
+{
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	unsigned int timeout;
+	int i;
+
+	dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
+
+	mpt_event_deregister(LanCtx);
+
+	dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
+		  "since driver was loaded, %d still out\n",
+		  priv->total_posted,atomic_read(&priv->buckets_out)));
+
+	netif_stop_queue(dev);
+
+	mpt_lan_reset(dev);
+
+	timeout = 2 * HZ;
+	while (atomic_read(&priv->buckets_out) && --timeout) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+
+	for (i = 0; i < priv->max_buckets_out; i++) {
+		if (priv->RcvCtl[i].skb != NULL) {
+/**/			dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
+/**/				  "is still out\n", i));
+			pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma,
+				 	 priv->RcvCtl[i].len,
+					 PCI_DMA_FROMDEVICE);
+ 			dev_kfree_skb(priv->RcvCtl[i].skb);
+		}
+	}
+
+	kfree (priv->RcvCtl);
+	kfree (priv->mpt_rxfidx);
+
+	for (i = 0; i < priv->tx_max_out; i++) {
+ 		if (priv->SendCtl[i].skb != NULL) {
+			pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma,
+					 priv->SendCtl[i].len,
+					 PCI_DMA_TODEVICE);
+ 			dev_kfree_skb(priv->SendCtl[i].skb);
+		}
+	}
+
+	kfree(priv->SendCtl);
+	kfree(priv->mpt_txfidx);
+
+	atomic_set(&priv->buckets_out, 0);
+
+	printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev));
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct net_device_stats *
+mpt_lan_get_stats(struct net_device *dev)
+{
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+	return (struct net_device_stats *) &priv->stats;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Tx timeout handler. */
+static void
+mpt_lan_tx_timeout(struct net_device *dev)
+{
+	netif_wake_queue(dev);  
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
+{
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	struct sk_buff *sent;
+	unsigned long flags;
+	u32 ctx;
+
+	ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
+	sent = priv->SendCtl[ctx].skb;
+
+	priv->stats.tx_packets++;
+	priv->stats.tx_bytes += sent->len;
+
+	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev),
+			__FUNCTION__, sent));
+
+	priv->SendCtl[ctx].skb = NULL;
+	pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+			 priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+	dev_kfree_skb_irq(sent);
+
+	spin_lock_irqsave(&priv->txfidx_lock, flags);
+	priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+	spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+	netif_wake_queue(dev);
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
+{
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	struct sk_buff *sent;
+	unsigned long flags;
+	int FreeReqFrame = 0;
+	u32 *pContext;
+	u32 ctx;
+	u8 count;
+
+	count = pSendRep->NumberOfContexts;
+
+	dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n",
+		 le16_to_cpu(pSendRep->IOCStatus)));
+
+	/* Add check for Loginfo Flag in IOCStatus */
+
+	switch (le16_to_cpu(pSendRep->IOCStatus)) {
+	case MPI_IOCSTATUS_SUCCESS:
+		priv->stats.tx_packets += count;
+		break;
+
+	case MPI_IOCSTATUS_LAN_CANCELED:
+	case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED:
+		break;
+
+	case MPI_IOCSTATUS_INVALID_SGL:
+		priv->stats.tx_errors += count;
+		printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n",
+				IOC_AND_NETDEV_NAMES_s_s(dev));
+		goto out;
+
+	default:
+		priv->stats.tx_errors += count;
+		break;
+	}
+
+	pContext = &pSendRep->BufferContext;
+
+	spin_lock_irqsave(&priv->txfidx_lock, flags);
+	while (count > 0) {
+		ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
+
+		sent = priv->SendCtl[ctx].skb;
+		priv->stats.tx_bytes += sent->len;
+
+		dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+				IOC_AND_NETDEV_NAMES_s_s(dev),
+				__FUNCTION__, sent));
+
+		priv->SendCtl[ctx].skb = NULL;
+		pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+				 priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(sent);
+
+		priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+
+		pContext++;
+		count--;
+	}
+	spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+out:
+	if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+		FreeReqFrame = 1;
+
+	netif_wake_queue(dev);
+	return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
+{
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	MPT_FRAME_HDR *mf;
+	LANSendRequest_t *pSendReq;
+	SGETransaction32_t *pTrans;
+	SGESimple64_t *pSimple;
+	dma_addr_t dma;
+	unsigned long flags;
+	int ctx;
+
+	dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
+			__FUNCTION__, skb));
+
+	spin_lock_irqsave(&priv->txfidx_lock, flags);
+	if (priv->mpt_txfidx_tail < 0) {
+		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+		printk (KERN_ERR "%s: no tx context available: %u\n",
+			__FUNCTION__, priv->mpt_txfidx_tail);
+		return 1;
+	}
+
+	mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+	if (mf == NULL) {
+		netif_stop_queue(dev);
+		dev_kfree_skb(skb);
+		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+		printk (KERN_ERR "%s: Unable to alloc request frame\n",
+			__FUNCTION__);
+		return 1;
+	}
+
+	ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--];
+	spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+//	dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n",
+//			IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+	pSendReq = (LANSendRequest_t *) mf;
+
+	/* Set the mac.raw pointer, since this apparently isn't getting
+	 * done before we get the skb. Pull the data pointer past the mac data.
+	 */
+	skb->mac.raw = skb->data;
+	skb_pull(skb, 12);
+
+        dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
+			     PCI_DMA_TODEVICE);
+
+	priv->SendCtl[ctx].skb = skb;
+	priv->SendCtl[ctx].dma = dma;
+	priv->SendCtl[ctx].len = skb->len;
+
+	/* Message Header */
+	pSendReq->Function    = MPI_FUNCTION_LAN_SEND;
+	pSendReq->ChainOffset = 0;
+	pSendReq->MsgFlags    = 0;
+	pSendReq->PortNumber  = priv->pnum;
+
+	/* Transaction Context Element */
+	pTrans = (SGETransaction32_t *) pSendReq->SG_List;
+
+	/* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */
+	pTrans->ContextSize   = sizeof(u32);
+	pTrans->DetailsLength = 2 * sizeof(u32);
+	pTrans->Flags         = 0;
+	pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+//	dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n",
+//			IOC_AND_NETDEV_NAMES_s_s(dev),
+//			ctx, skb, skb->data));
+
+	pTrans->TransactionDetails[0] = cpu_to_le32((0x1000          << 16) |
+						    (skb->mac.raw[0] <<  8) |
+						    (skb->mac.raw[1] <<  0));
+	pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
+						    (skb->mac.raw[3] << 16) |
+						    (skb->mac.raw[4] <<  8) |
+						    (skb->mac.raw[5] <<  0));
+
+	pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
+
+	pSimple->FlagsLength = cpu_to_le32(
+			((MPI_SGE_FLAGS_END_OF_BUFFER |
+			  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+			  MPI_SGE_FLAGS_64_BIT_ADDRESSING |
+			  MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) |
+			skb->len);
+	pSimple->Address.Low = cpu_to_le32((u32) dma);
+	if (sizeof(dma_addr_t) > sizeof(u32))
+		pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32));
+	else
+		pSimple->Address.High = 0;
+
+	mpt_put_msg_frame (LanCtx, mpt_dev->id, mf);
+	dev->trans_start = jiffies;
+
+	dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
+		 	IOC_AND_NETDEV_NAMES_s_s(dev),
+		       	le32_to_cpu(pSimple->FlagsLength)));
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline void
+mpt_lan_wake_post_buckets_task(struct net_device *dev)
+{
+	struct mpt_lan_priv *priv = dev->priv;
+
+	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
+		queue_task(&priv->post_buckets_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
+				IOC_AND_NETDEV_NAMES_s_s(dev) ));
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline int
+mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
+{
+	struct mpt_lan_priv *priv = dev->priv;
+
+	skb->protocol = mpt_lan_type_trans(skb, dev);
+
+	dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " 
+		 "delivered to upper level.\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
+
+	priv->stats.rx_bytes += skb->len;
+	priv->stats.rx_packets++;
+
+	skb->dev = dev;
+	netif_rx(skb);
+
+	dioprintk((MYNAM "/receive_skb: %d buckets remaining\n",
+		 atomic_read(&priv->buckets_out)));
+
+	if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
+		mpt_lan_wake_post_buckets_task(dev);
+
+	dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
+		  "remaining, %d received back since sod\n",
+		  atomic_read(&priv->buckets_out), priv->total_received));
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
+{
+	struct mpt_lan_priv *priv = dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	struct sk_buff *skb, *old_skb;
+	unsigned long flags;
+	u32 ctx, len;
+
+	ctx = GET_LAN_BUCKET_CONTEXT(tmsg);
+	skb = priv->RcvCtl[ctx].skb;
+
+	len = GET_LAN_PACKET_LENGTH(tmsg);
+
+	if (len < MPT_LAN_RX_COPYBREAK) {
+		old_skb = skb;
+
+		skb = (struct sk_buff *)dev_alloc_skb(len);
+		if (!skb) {
+			printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+					IOC_AND_NETDEV_NAMES_s_s(dev),
+					__FILE__, __LINE__);
+			return -ENOMEM;
+		}
+
+		pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+				    priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+		memcpy(skb_put(skb, len), old_skb->data, len);
+
+		goto out;
+	}
+
+	skb_put(skb, len);
+
+	priv->RcvCtl[ctx].skb = NULL;
+
+	pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+			 priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+out:
+	spin_lock_irqsave(&priv->rxfidx_lock, flags);
+	priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+	spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+	atomic_dec(&priv->buckets_out);
+	priv->total_received++;
+
+	return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_free(struct net_device *dev,
+			  LANReceivePostReply_t *pRecvRep)
+{
+	struct mpt_lan_priv *priv = dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	unsigned long flags;
+	struct sk_buff *skb;
+	u32 ctx;
+	u8 count;
+	int i;
+
+	count = pRecvRep->NumberOfContexts;
+
+/**/	dprintk((KERN_INFO MYNAM "/receive_post_reply: "
+		  "IOC returned %d buckets, freeing them...\n", count));
+
+	spin_lock_irqsave(&priv->rxfidx_lock, flags);
+	for (i = 0; i < count; i++) {
+		ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+
+		skb = priv->RcvCtl[ctx].skb;
+
+//		dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
+//				IOC_AND_NETDEV_NAMES_s_s(dev)));
+//		dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
+//			  	priv, &(priv->buckets_out)));
+//		dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
+
+		priv->RcvCtl[ctx].skb = NULL;
+		pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+				 priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(skb);
+
+		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+	}
+	spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+	atomic_sub(count, &priv->buckets_out);
+
+//	for (i = 0; i < priv->max_buckets_out; i++)
+//		if (priv->RcvCtl[i].skb != NULL)
+//			dprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
+//				  "is still out\n", i));
+
+/*	dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
+		  count));
+*/
+/**/	dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
+/**/		  "remaining, %d received back since sod.\n",
+/**/		  atomic_read(&priv->buckets_out), priv->total_received));
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_reply(struct net_device *dev,
+			   LANReceivePostReply_t *pRecvRep)
+{
+	struct mpt_lan_priv *priv = dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	struct sk_buff *skb, *old_skb;
+	unsigned long flags;
+	u32 len, ctx;
+	u32 offset;
+	u8 count;
+	int i, l;
+
+	dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n"));
+	dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n",
+		 le16_to_cpu(pRecvRep->IOCStatus)));
+
+	if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED)
+		return mpt_lan_receive_post_free(dev, pRecvRep);
+
+	len = le32_to_cpu(pRecvRep->PacketLength);
+	if (len == 0) {
+		printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO "
+			"ReceivePostReply w/ PacketLength zero!\n",
+				IOC_AND_NETDEV_NAMES_s_s(dev));
+		printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n",
+				pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus));
+		return -1;
+	}
+
+	ctx    = le32_to_cpu(pRecvRep->BucketContext[0]);
+	count  = pRecvRep->NumberOfContexts;
+	skb    = priv->RcvCtl[ctx].skb;
+
+	offset = le32_to_cpu(pRecvRep->PacketOffset);
+//	if (offset != 0) {
+//		printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply "
+//			"w/ PacketOffset %u\n",
+//				IOC_AND_NETDEV_NAMES_s_s(dev),
+//				offset);
+//	}
+
+	dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev),
+			offset, len));
+
+	if (count > 1) {
+		int szrem = len;
+
+//		dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned "
+//			"for single packet, concatenating...\n",
+//				IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+		skb = (struct sk_buff *)dev_alloc_skb(len);
+		if (!skb) {
+			printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+					IOC_AND_NETDEV_NAMES_s_s(dev),
+			       		__FILE__, __LINE__);
+			return -ENOMEM;
+		}
+
+		spin_lock_irqsave(&priv->rxfidx_lock, flags);
+		for (i = 0; i < count; i++) {
+
+			ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+			old_skb = priv->RcvCtl[ctx].skb;
+
+			l = priv->RcvCtl[ctx].len;
+			if (szrem < l)
+				l = szrem;
+
+//			dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n",
+//					IOC_AND_NETDEV_NAMES_s_s(dev),
+//					i, l));
+
+			pci_dma_sync_single(mpt_dev->pcidev,
+					    priv->RcvCtl[ctx].dma,
+					    priv->RcvCtl[ctx].len,
+					    PCI_DMA_FROMDEVICE);
+			memcpy(skb_put(skb, l), old_skb->data, l);
+
+			priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+			szrem -= l;
+		}
+		spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+	} else if (len < MPT_LAN_RX_COPYBREAK) {
+
+		old_skb = skb;
+
+		skb = (struct sk_buff *)dev_alloc_skb(len);
+		if (!skb) {
+			printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+					IOC_AND_NETDEV_NAMES_s_s(dev),
+			       		__FILE__, __LINE__);
+			return -ENOMEM;
+		}
+
+		pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+				    priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+		memcpy(skb_put(skb, len), old_skb->data, len);
+
+		spin_lock_irqsave(&priv->rxfidx_lock, flags);
+		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+		spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+	} else {
+		spin_lock_irqsave(&priv->rxfidx_lock, flags);
+
+		priv->RcvCtl[ctx].skb = NULL;
+
+		pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+				 priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+		priv->RcvCtl[ctx].dma = 0;
+
+		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+		spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+		skb_put(skb,len);
+	}
+
+	atomic_sub(count, &priv->buckets_out);
+	priv->total_received += count;
+
+	if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) {
+		printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, "
+			"MPT_LAN_MAX_BUCKETS_OUT = %d\n",
+				IOC_AND_NETDEV_NAMES_s_s(dev),
+				priv->mpt_rxfidx_tail,
+				MPT_LAN_MAX_BUCKETS_OUT);
+
+		panic("Damn it Jim! I'm a doctor, not a programmer! "
+				"Oh, wait a sec, I am a programmer. "
+				"And, who's Jim?!?!\n"
+				"Arrgghh! We've done it again!\n");
+	}
+
+#if 0
+	{
+		u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
+		if (remaining < priv->bucketthresh)
+			mpt_lan_wake_post_buckets_task(dev);
+
+		if (remaining == 0)
+			printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
+				"(priv->buckets_out = %d)\n",
+					IOC_AND_NETDEV_NAMES_s_s(dev),
+					atomic_read(&priv->buckets_out));
+		else
+			printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
+				"(priv->buckets_out = %d)\n",
+					IOC_AND_NETDEV_NAMES_s_s(dev),
+					remaining, atomic_read(&priv->buckets_out));
+	}
+#endif
+
+	return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Simple SGE's only at the moment */
+
+static void
+mpt_lan_post_receive_buckets(void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct mpt_lan_priv *priv = dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+	MPT_FRAME_HDR *mf;
+	LANReceivePostRequest_t *pRecvReq;
+	SGETransaction32_t *pTrans;
+	SGESimple64_t *pSimple;
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	u32 curr, buckets, count, max;
+	u32 len = (dev->mtu + dev->hard_header_len + 4);
+	unsigned long flags;
+	int i;
+
+	curr = atomic_read(&priv->buckets_out);
+	buckets = (priv->max_buckets_out - curr);
+
+	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev),
+			__FUNCTION__, buckets, curr));
+
+	max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
+			(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
+
+	while (buckets) {
+		mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+		if (mf == NULL) {
+			printk (KERN_ERR "%s: Unable to alloc request frame\n",
+				__FUNCTION__);
+			dioprintk((KERN_ERR "%s: %u buckets remaining\n",
+				 __FUNCTION__, buckets));
+			goto out;
+		}
+		pRecvReq = (LANReceivePostRequest_t *) mf;
+
+		count = buckets;
+		if (count > max)
+			count = max;
+
+		pRecvReq->Function    = MPI_FUNCTION_LAN_RECEIVE;
+		pRecvReq->ChainOffset = 0;
+		pRecvReq->MsgFlags    = 0;
+		pRecvReq->PortNumber  = priv->pnum;
+
+		pTrans = (SGETransaction32_t *) pRecvReq->SG_List;
+		pSimple = NULL;
+
+		for (i = 0; i < count; i++) {
+			int ctx;
+
+			spin_lock_irqsave(&priv->rxfidx_lock, flags);
+			if (priv->mpt_rxfidx_tail < 0) {
+				printk (KERN_ERR "%s: Can't alloc context\n",
+					__FUNCTION__);
+				spin_unlock_irqrestore(&priv->rxfidx_lock,
+						       flags);
+				break;
+			}
+
+			ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--];
+
+			skb = priv->RcvCtl[ctx].skb;
+			if (skb && (priv->RcvCtl[ctx].len != len)) {
+				pci_unmap_single(mpt_dev->pcidev,
+						 priv->RcvCtl[ctx].dma,
+						 priv->RcvCtl[ctx].len,
+						 PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(priv->RcvCtl[ctx].skb);
+				skb = priv->RcvCtl[ctx].skb = NULL;
+			}
+
+			if (skb == NULL) {
+				skb = dev_alloc_skb(len);
+				if (skb == NULL) {
+/**/					printk (KERN_WARNING
+/**/						MYNAM "/%s: Can't alloc skb\n",
+/**/						__FUNCTION__);
+					priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+					spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+					break;
+				}
+
+		    		dma = pci_map_single(mpt_dev->pcidev, skb->data,
+						     len, PCI_DMA_FROMDEVICE);
+
+				priv->RcvCtl[ctx].skb = skb;
+				priv->RcvCtl[ctx].dma = dma;
+				priv->RcvCtl[ctx].len = len;
+			}
+
+			spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+			pTrans->ContextSize   = sizeof(u32);
+			pTrans->DetailsLength = 0;
+			pTrans->Flags         = 0;
+			pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+			pSimple = (SGESimple64_t *) pTrans->TransactionDetails;
+
+			pSimple->FlagsLength = cpu_to_le32(
+				((MPI_SGE_FLAGS_END_OF_BUFFER |
+				  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+				  MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len);
+			pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma);
+			if (sizeof(dma_addr_t) > sizeof(u32))
+				pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32));
+			else
+				pSimple->Address.High = 0;
+
+			pTrans = (SGETransaction32_t *) (pSimple + 1);
+		}
+
+		if (pSimple == NULL) {
+/**/			printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
+/**/				__FUNCTION__);
+			mpt_free_msg_frame(LanCtx, mpt_dev->id, mf);
+			goto out;
+		}
+
+		pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT);
+
+		pRecvReq->BucketCount = cpu_to_le32(i);
+
+/*	printk(KERN_INFO MYNAM ": posting buckets\n   ");
+ *	for (i = 0; i < j + 2; i ++)
+ *	    printk (" %08x", le32_to_cpu(msg[i]));
+ *	printk ("\n");
+ */
+
+		mpt_put_msg_frame(LanCtx, mpt_dev->id, mf);
+
+		priv->total_posted += i;
+		buckets -= i;
+		atomic_add(i, &priv->buckets_out);
+	}
+
+out:
+	dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
+		  __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+	dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
+	__FUNCTION__, priv->total_posted, priv->total_received)); 
+
+	clear_bit(0, &priv->post_buckets_active);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+struct net_device *
+mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
+{
+	struct net_device *dev = NULL;
+	struct mpt_lan_priv *priv = NULL;
+	u8 HWaddr[FC_ALEN], *a;
+
+	dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv));
+	if (!dev)
+		return (NULL);
+	dev->mtu = MPT_LAN_MTU;
+
+	priv = (struct mpt_lan_priv *) dev->priv;
+
+	priv->mpt_dev = mpt_dev;
+	priv->pnum = pnum;
+
+	memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct));
+	priv->post_buckets_task.routine = mpt_lan_post_receive_buckets;
+	priv->post_buckets_task.data = dev;
+	priv->post_buckets_active = 0;
+
+	dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+			__LINE__, dev->mtu + dev->hard_header_len + 4));
+
+	atomic_set(&priv->buckets_out, 0);
+	priv->total_posted = 0;
+	priv->total_received = 0;
+	priv->max_buckets_out = max_buckets_out;
+	if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out)
+		priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets;
+
+	dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
+			__LINE__,
+			mpt_dev->pfacts0.MaxLanBuckets,
+			max_buckets_out,
+			priv->max_buckets_out));
+
+	priv->bucketthresh = priv->max_buckets_out * 2 / 3;
+	priv->txfidx_lock = SPIN_LOCK_UNLOCKED;
+	priv->rxfidx_lock = SPIN_LOCK_UNLOCKED;
+
+	memset(&priv->stats, 0, sizeof(priv->stats));
+
+	/*  Grab pre-fetched LANPage1 stuff. :-) */
+	a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
+
+	HWaddr[0] = a[5];
+	HWaddr[1] = a[4];
+	HWaddr[2] = a[3];
+	HWaddr[3] = a[2];
+	HWaddr[4] = a[1];
+	HWaddr[5] = a[0];
+
+	dev->addr_len = FC_ALEN;
+	memcpy(dev->dev_addr, HWaddr, FC_ALEN);
+	memset(dev->broadcast, 0xff, FC_ALEN);
+
+	/* The Tx queue is 127 deep on the 909.
+	 * Give ourselves some breathing room.
+	 */
+	priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
+			    tx_max_out_p : MPT_TX_MAX_OUT_LIM;
+
+	dev->open = mpt_lan_open;
+	dev->stop = mpt_lan_close;
+	dev->get_stats = mpt_lan_get_stats;
+	dev->set_multicast_list = NULL;
+	dev->change_mtu = mpt_lan_change_mtu;
+	dev->hard_start_xmit = mpt_lan_sdu_send;
+
+/* Not in 2.3.42. Need 2.3.45+ */
+	dev->tx_timeout = mpt_lan_tx_timeout;
+	dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
+
+	dprintk((KERN_INFO MYNAM ": Finished registering dev "
+		"and setting initial values\n"));
+
+	SET_MODULE_OWNER(dev);
+
+	return dev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init
+mpt_lan_init (void)
+{
+	struct net_device *dev;
+	MPT_ADAPTER *curadapter;
+	int i = 0, j;
+
+	show_mptmod_ver(LANAME, LANVER);
+
+	if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) {
+		printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
+		return -EBUSY;
+	}
+
+	/* Set the callback index to be used by driver core for turbo replies */
+	mpt_lan_index = LanCtx;
+
+	dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
+
+	for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
+		mpt_landev[j] = NULL;
+	}
+	j = 0;
+
+	curadapter = mpt_adapter_find_first();
+	while (curadapter != NULL) {
+		for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) {
+			printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n",
+					curadapter->name,
+					curadapter->pfacts0.PortNumber,
+					curadapter->pfacts0.ProtocolFlags,
+					MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags));
+
+			if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+				dev = mpt_register_lan_device (curadapter, i);
+				if (dev != NULL) {
+					printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n",
+							curadapter->name, dev->name);
+					printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+							IOC_AND_NETDEV_NAMES_s_s(dev),
+							dev->dev_addr[0], dev->dev_addr[1],
+							dev->dev_addr[2], dev->dev_addr[3],
+							dev->dev_addr[4], dev->dev_addr[5]);
+//					printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n",
+//							IOC_AND_NETDEV_NAMES_s_s(dev),
+//							NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
+					mpt_landev[j] = dev;
+					dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
+							dev, j,  mpt_landev[j]));
+
+					j++;
+				} else {
+					printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
+							curadapter->name,
+							curadapter->pfacts0.PortNumber);
+				}
+			} else {
+				printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n",
+						curadapter->name);
+			}
+		}
+		curadapter = mpt_adapter_find_next(curadapter);
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void __init mpt_lan_exit(void)
+{
+	int i;
+
+	for (i = 0; mpt_landev[i] != NULL; i++) {
+		struct net_device *dev = mpt_landev[i];
+
+		printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n",
+			       IOC_AND_NETDEV_NAMES_s_s(dev));
+		unregister_fcdev(dev);
+		mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */
+	}
+
+	if (LanCtx >= 0) {
+		mpt_deregister(LanCtx);
+		LanCtx = -1;
+		mpt_lan_index = 0;
+	}
+
+	/* deregister any send/receive handler structs. I2Oism? */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+MODULE_PARM(tx_max_out_p, "i");
+MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
+
+module_init(mpt_lan_init);
+module_exit(mpt_lan_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static unsigned short
+mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) 
+{
+	struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
+	struct fcllc *fcllc;
+
+	skb->mac.raw = skb->data;
+	skb_pull(skb, sizeof(struct mpt_lan_ohdr));
+
+	if (fch->dtype == htons(0xffff)) {
+		u32 *p = (u32 *) fch;
+
+		swab32s(p + 0);
+		swab32s(p + 1);
+		swab32s(p + 2);
+		swab32s(p + 3);
+
+		printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
+				NETDEV_PTR_TO_IOC_NAME_s(dev));
+		printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       		fch->saddr[0], fch->saddr[1], fch->saddr[2],
+				fch->saddr[3], fch->saddr[4], fch->saddr[5]);
+	}
+
+	if (*fch->daddr & 1) {
+		if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) {
+			skb->pkt_type = PACKET_BROADCAST;
+		} else {
+			skb->pkt_type = PACKET_MULTICAST;
+		}
+	} else {
+		if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) {
+			skb->pkt_type = PACKET_OTHERHOST;
+		} else {
+			skb->pkt_type = PACKET_HOST;
+		}
+	}
+
+	/* Strip the SNAP header from ARP packets since we don't 
+	 * pass them through to the 802.2/SNAP layers.
+	 */
+	fcllc = (struct fcllc *)skb->data;
+
+	if (fcllc->dsap == EXTENDED_SAP &&
+		(fcllc->ethertype == htons(ETH_P_IP) ||
+		 fcllc->ethertype == htons(ETH_P_ARP))) {
+		skb_pull(skb, sizeof(struct fcllc));
+		return fcllc->ethertype;
+	}
+
+	return htons(ETH_P_802_2);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptlan.h linux/drivers/message/fusion/mptlan.h
--- v2.4.6/linux/drivers/message/fusion/mptlan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptlan.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,72 @@
+/* mptlan.h */
+
+#ifndef LINUX_MPTLAN_H_INCLUDED
+#define LINUX_MPTLAN_H_INCLUDED
+/*****************************************************************************/
+
+#if !defined(__GENKSYMS__)
+#include <linux/module.h>
+#endif
+
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+// #include <linux/etherdevice.h>
+#include <linux/fcdevice.h>
+// #include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/tqueue.h>
+// #include <linux/trdevice.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+    /* Override mptbase.h by pre-defining these! */
+    #define MODULEAUTHOR "Noah Romer, Eddie C. Dost"
+
+#include "mptbase.h"
+
+/*****************************************************************************/
+#define LANAME		"Fusion MPT LAN driver"
+#define LANVER		MPT_LINUX_VERSION_COMMON
+
+#ifdef MODULE
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(LANAME);
+#endif
+/*****************************************************************************/
+
+#define MPT_LAN_MAX_BUCKETS_OUT 256
+#define MPT_LAN_BUCKET_THRESH	18 /* 9 buckets in one message */
+#define MPT_LAN_RX_COPYBREAK	200
+#define MPT_LAN_TX_TIMEOUT 	(1*HZ)
+#define MPT_TX_MAX_OUT_LIM      127
+
+#define MPT_LAN_MIN_MTU		96		/* RFC2625 */
+#define MPT_LAN_MAX_MTU		65280		/* RFC2625 */
+#define MPT_LAN_MTU             16128		/* be nice to slab allocator */
+
+/* MPT LAN Reset and Suspend Resource Flags Defines */
+
+#define MPT_LAN_RESOURCE_FLAG_RETURN_POSTED_BUCKETS    0x01
+#define MPT_LAN_RESOURCE_FLAG_RETURN_PEND_TRANSMITS    0x02
+
+/*****************************************************************************/
+#ifdef MPT_LAN_IO_DEBUG
+#define dioprintk(x)  printk x
+#else
+#define dioprintk(x)
+#endif
+
+#define NETDEV_TO_LANPRIV_PTR(d)	((struct mpt_lan_priv *)(d)->priv)
+#define NETDEV_PTR_TO_IOC_NAME_s(d)	(NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name)
+#define IOC_AND_NETDEV_NAMES_s_s(d)	NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name
+
+/*****************************************************************************/
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptscsih.c linux/drivers/message/fusion/mptscsih.c
--- v2.4.6/linux/drivers/message/fusion/mptscsih.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptscsih.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,2508 @@
+/*
+ *  linux/drivers/message/fusion/mptscsih.c
+ *      High performance SCSI / Fibre Channel SCSI Host device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Original author: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptscsih.c,v 1.24 2001/03/22 08:45:08 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>		/* for io_request_lock (spinlock) decl */
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
+
+#include "mptbase.h"
+#include "mptscsih.h"
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME		"Fusion MPT SCSI Host driver"
+#define my_VERSION	MPT_LINUX_VERSION_COMMON
+#define MYNAM		"mptscsih"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+typedef struct _BIG_SENSE_BUF {
+	u8		data[256];
+} BIG_SENSE_BUF;
+
+typedef struct _MPT_SCSI_HOST {
+	MPT_ADAPTER		 *ioc;
+	int			  port;
+	struct scsi_cmnd	**ScsiLookup;
+	u8			 *SgHunks;
+	dma_addr_t		  SgHunksDMA;
+	u32			  qtag_tick;
+	FCDEV_TRACKER		  TargetsQ;
+} MPT_SCSI_HOST;
+
+typedef struct _MPT_SCSI_DEV {
+	struct _MPT_SCSI_DEV	 *forw;
+	struct _MPT_SCSI_DEV	 *back;
+	MPT_ADAPTER		 *ioc;
+	int			  sense_sz;
+	BIG_SENSE_BUF		  CachedSense;
+	unsigned long		  io_cnt;
+	unsigned long		  read_cnt;
+} MPT_SCSI_DEV;
+
+/*
+ *  Other private/forward protos...
+ */
+
+static int	mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void	mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
+static int	mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static int	mptscsih_io_direction(Scsi_Cmnd *cmd);
+static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
+static u32	SCPNT_TO_MSGCTX(Scsi_Cmnd *sc);
+
+static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+
+
+static int	mpt_scsi_hosts = 0;
+static atomic_t	queue_depth;
+
+static int	ScsiDoneCtx = -1;
+static int	ScsiTaskCtx = -1;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+static struct proc_dir_entry proc_mpt_scsihost =
+{
+	low_ino:	PROC_SCSI_MPT,
+	namelen:	8,
+	name:		"mptscsih",
+	mode:		S_IFDIR | S_IRUGO | S_IXUGO,
+	nlink:		2,
+};
+#endif
+
+#define SNS_LEN(scp)  sizeof((scp)->sense_buffer)
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*
+ *  Stuff to handle single-threading SCSI TaskMgmt
+ *  (abort/reset) requests...
+ */
+static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED;
+static MPT_Q_TRACKER mpt_scsih_taskQ = {
+	(MPT_FRAME_HDR*) &mpt_scsih_taskQ,
+	(MPT_FRAME_HDR*) &mpt_scsih_taskQ
+};
+static int mpt_scsih_taskQ_cnt = 0;
+static int mpt_scsih_taskQ_bh_active = 0;
+static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_io_done - Main SCSI IO callback routine registered to
+ *	Fusion MPT (base) driver
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mf: Pointer to original MPT request frame
+ *	@r: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *	This routine is called from mpt.c::mpt_interrupt() at the completion
+ *	of any SCSI IO request.
+ *	This routine is registered with the Fusion MPT (base) driver at driver
+ *	load/init time via the mpt_register() API call.
+ *
+ *	Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+{
+	Scsi_Cmnd	*sc;
+	MPT_SCSI_HOST	*hd;
+	MPT_SCSI_DEV	*mpt_sdev = NULL;
+	u16		 req_idx;
+
+	if ((mf == NULL) ||
+	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+		printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf);
+		return 1;
+	}
+
+	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+	sc = hd->ScsiLookup[req_idx];
+	hd->ScsiLookup[req_idx] = NULL;
+
+	dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+
+	atomic_dec(&queue_depth);
+
+	/*
+	 *  Check for {1st} {IO} completion to "new" device.
+	 *  How do we know it's a new device?
+	 *  If we haven't set SDpnt->hostdata I guess...
+	 */
+	if (sc && sc->device) {
+		mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata;
+		if (!mpt_sdev) {
+			dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n",
+					   sc->device->id, sc->device->lun, sc->device->channel));
+			if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) {
+				printk(KERN_ERR MYNAM ": ERROR: kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV));
+			} else {
+				memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV));
+				mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata;
+				mpt_sdev->ioc = ioc;
+			}
+		} else {
+			if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) {
+				if (++mpt_sdev->read_cnt == 3) {
+					dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n",
+							sc->cmnd[0]));
+				}
+			}
+#if 0
+			if (mpt_sdev->sense_sz) {
+				/*
+				 *  Completion of first IO down this path
+				 *  *should* invalidate device SenseData...
+				 */
+				mpt_sdev->sense_sz = 0;
+			}
+#endif
+		}
+	}
+
+#if 0
+{
+	MPT_FRAME_HDR	*mf_chk;
+
+	/* This, I imagine, is a costly check, but...
+	 *  If abort/reset active, check to see if this is a IO
+	 *  that completed while ABORT/RESET for it is waiting
+	 *  on our taskQ!
+	 */
+	if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+		/* If ABORT for this IO is queued, zap it! */
+		mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+		if (mf_chk != NULL) {
+			sc->result = DID_ABORT << 16;
+			spin_lock_irqsave(&io_request_lock, flags);
+			sc->scsi_done(sc);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			return 1;
+		}
+	}
+}
+#endif
+
+	if (r != NULL && sc != NULL) {
+		SCSIIOReply_t	*pScsiReply;
+		SCSIIORequest_t *pScsiReq;
+		u16		 status;
+
+		pScsiReply = (SCSIIOReply_t *) r;
+		pScsiReq = (SCSIIORequest_t *) mf;
+
+		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+		dprintk((KERN_NOTICE MYNAM ": Uh-Oh!  (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+		dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
+				     ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+				     status, pScsiReply->SCSIState, pScsiReply->SCSIStatus,
+				     le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+		/*
+		 *  Look for + dump FCP ResponseInfo[]!
+		 */
+		if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+			dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
+					     le32_to_cpu(pScsiReply->ResponseInfo)));
+		}
+
+		switch(status) {
+		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
+			/*sc->result = DID_BUS_BUSY << 16;*/		/* YIKES! - Seems to
+									 * kill linux interrupt
+									 * handler
+									 */
+			sc->result = STS_BUSY;				/* Try SCSI BUSY! */
+			break;
+
+		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
+			/*  Not real sure here...  */
+			sc->result = DID_OK << 16;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */
+		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */
+			sc->result = DID_BAD_TARGET << 16;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
+			/*  Spoof to SCSI Selection Timeout!  */
+			sc->result = DID_NO_CONNECT << 16;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
+			/*
+			 *  YIKES!  I just discovered that SCSI IO which
+			 *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)
+			 *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
+			 *  comes down this path!
+			 *  Do upfront check for valid SenseData and give it
+			 *  precedence!
+			 */
+			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+				copy_sense_data(sc, hd, mf, pScsiReply);
+				sc->result = pScsiReply->SCSIStatus;
+				break;
+			}
+
+			dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow));
+			dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount)));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+			sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
+			dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid));
+#endif
+
+#if 0
+			if (sc->underflow && (le32_to_cpu(pScsiReply->TransferCount) < sc->underflow)) {
+				sc->result = DID_ERROR << 16;
+				sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
+			} else {
+				sc->result = 0;
+			}
+#endif
+
+			/* workaround attempts... */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+			if (sc->resid >= 0x200) {
+				/* GRRRRR...
+				 *   //sc->result = DID_SOFT_ERROR << 16;
+				 * Try spoofing to BUSY
+				 */
+				sc->result = STS_BUSY;
+			} else {
+				sc->result = 0;
+			}
+#else
+			sc->result = 0;
+#endif
+			break;
+
+		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
+			sc->result = DID_ABORT << 16;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
+		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
+			sc->result = DID_RESET << 16;
+			break;
+
+		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
+			sc->result = pScsiReply->SCSIStatus;
+
+			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+				copy_sense_data(sc, hd, mf, pScsiReply);
+
+				/*  If running agains circa 200003dd 909 MPT f/w,
+				 *  may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
+				 *  (QUEUE_FULL) returned from device!	--> get 0x0000?128
+				 *  and with SenseBytes set to 0.
+				 */
+				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
+					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+			}
+			else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+				/*
+				 *  What to do?
+				 */
+				sc->result = DID_SOFT_ERROR << 16;
+			}
+			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+				/*  Not real sure here either...  */
+				sc->result = DID_ABORT << 16;
+			}
+
+			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+			break;
+
+		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */
+		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */
+		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */
+		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */
+		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */
+		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */
+		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
+		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
+		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
+		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
+		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
+		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
+		default:
+			/*
+			 *  What to do?
+			 */
+			sc->result = DID_SOFT_ERROR << 16;
+			break;
+
+		}	/* switch(status) */
+
+		dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result));
+	}
+
+	if (sc != NULL) {
+		unsigned long flags;
+
+		/* Unmap the DMA buffers, if any. */
+		if (sc->use_sg) {
+			pci_unmap_sg(ioc->pcidev,
+				     (struct scatterlist *) sc->request_buffer,
+				     sc->use_sg,
+				     scsi_to_pci_dma_dir(sc->sc_data_direction));
+		} else if (sc->request_bufflen) {
+			pci_unmap_single(ioc->pcidev,
+					 (dma_addr_t)((long)sc->SCp.ptr),
+					 sc->request_bufflen,
+					 scsi_to_pci_dma_dir(sc->sc_data_direction));
+		}
+
+		spin_lock_irqsave(&io_request_lock, flags);
+		sc->scsi_done(sc);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	}
+
+	return 1;
+}
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	search_taskQ - Search SCSI task mgmt request queue for specific
+ *			request type
+ *	@remove: (Boolean) Should request be removed if found?
+ *	@sc: Pointer to Scsi_Cmnd structure
+ *	@task_type: Task type to search for
+ *
+ *	Returns pointer to MPT request frame if found, or %NULL if request
+ *	was not found.
+ */
+static MPT_FRAME_HDR *
+search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type)
+{
+	MPT_FRAME_HDR *mf = NULL;
+	unsigned long flags;
+	int count = 0;
+	int list_sz;
+
+	dslprintk((KERN_INFO MYNAM ": spinlock#1\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	list_sz = mpt_scsih_taskQ_cnt;
+	if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+		mf = mpt_scsih_taskQ.head;
+		do {
+			count++;
+			if (mf->u.frame.linkage.argp1 == sc &&
+			    mf->u.frame.linkage.arg1 == task_type) {
+				if (remove) {
+					Q_DEL_ITEM(&mf->u.frame.linkage);
+					mpt_scsih_taskQ_cnt--;
+				}
+				break;
+			}
+		} while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ);
+		if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) {
+			mf = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+	if (list_sz) {
+		dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n",
+				   remove, sc, task_type,
+				   mf,
+				   mf ? "" : "NOT_",
+				   (mf && remove) ? "+REMOVED" : "" ));
+		dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n",
+				   count,
+				   list_sz ));
+	}
+
+	return mf;
+}
+
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Hack!  I'd like to report if a device is returning QUEUE_FULL
+ *  but maybe not each and every time...
+ */
+static long last_queue_full = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
+ *	from a SCSI target device.
+ *	@sc: Pointer to Scsi_Cmnd structure
+ *	@pScsiReply: Pointer to SCSIIOReply_t
+ *	@pScsiReq: Pointer to original SCSI request
+ *
+ *	This routine periodically reports QUEUE_FULL status returned from a
+ *	SCSI target device.  It reports this to the console via kernel
+ *	printk() API call, not more than once every 10 seconds.
+ */
+static void
+mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+{
+	long time = jiffies;
+
+	if (time - last_queue_full > 10 * HZ) {
+		printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL!  SCSI bus:target:lun = %d:%d:%d\n",
+				0, sc->target, sc->lun);
+		last_queue_full = time;
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int BeenHereDoneThat = 0;
+
+/*  SCSI fops start here...  */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
+ *	linux scsi mid-layer.
+ *	@tpnt: Pointer to Scsi_Host_Template structure
+ *
+ *	(linux Scsi_Host_Template.detect routine)
+ *
+ *	Returns number of SCSI host adapters that were successfully
+ *	registered with the linux scsi mid-layer via the scsi_register()
+ *	API call.
+ */
+int
+mptscsih_detect(Scsi_Host_Template *tpnt)
+{
+	struct Scsi_Host	*sh = NULL;
+	MPT_SCSI_HOST		*hd = NULL;
+	MPT_ADAPTER		*this;
+	unsigned long		 flags;
+	int			 sz;
+	u8			*mem;
+
+	if (! BeenHereDoneThat++) {
+		show_mptmod_ver(my_NAME, my_VERSION);
+
+		ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
+		ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+		Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
+		spin_lock_init(&mpt_scsih_taskQ_lock);
+#endif
+
+		if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
+			dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
+		} else {
+			/* FIXME! */
+		}
+	}
+
+	dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
+
+	this = mpt_adapter_find_first();
+	while (this != NULL) {
+		/* FIXME!  Multi-port (aka FC929) support...
+		 * for (i = 0; i < this->facts.NumberOfPorts; i++)
+		 */
+
+		/* 20010215 -sralston
+		 *  Added sanity check on SCSI Initiator-mode enabled
+		 *  for this MPT adapter.
+		 */
+		if (!(this->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
+			printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n",
+					this->name);
+			this = mpt_adapter_find_next(this);
+			continue;
+		}
+
+		/* 20010202 -sralston
+		 *  Added sanity check on readiness of the MPT adapter.
+		 */
+		if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+			printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n",
+					this->name);
+			this = mpt_adapter_find_next(this);
+			continue;
+		}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+		tpnt->proc_dir = &proc_mpt_scsihost;
+#endif
+		sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
+		if (sh != NULL) {
+			save_flags(flags);
+			cli();
+			sh->io_port = 0;
+			sh->n_io_port = 0;
+			sh->irq = 0;
+
+			/* Yikes!  This is important!
+			 * Otherwise, by default, linux only scans target IDs 0-7!
+			 */
+			sh->max_id = this->pfacts0.MaxDevices - 1;
+
+			sh->this_id = this->pfacts0.PortSCSIID;
+
+			restore_flags(flags);
+
+			hd = (MPT_SCSI_HOST *) sh->hostdata;
+			hd->ioc = this;
+			hd->port = 0;		/* FIXME! */
+
+			/* SCSI needs Scsi_Cmnd lookup table!
+			 * (with size equal to req_depth*PtrSz!)
+			 */
+			sz = hd->ioc->req_depth * sizeof(void *);
+			mem = kmalloc(sz, GFP_KERNEL);
+			if (mem == NULL)
+				return mpt_scsi_hosts;
+
+			memset(mem, 0, sz);
+			hd->ScsiLookup = (struct scsi_cmnd **) mem;
+
+			dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n",
+				 hd->ScsiLookup, sz));
+
+			/* SCSI also needs SG buckets/hunk management!
+			 * (with size equal to N * req_sz * req_depth!)
+			 * (where N is number of SG buckets per hunk)
+			 */
+			sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
+			mem = pci_alloc_consistent(hd->ioc->pcidev, sz,
+						   &hd->SgHunksDMA);
+			if (mem == NULL)
+				return mpt_scsi_hosts;
+
+			memset(mem, 0, sz);
+			hd->SgHunks = (u8*)mem;
+
+			dprintk((KERN_INFO MYNAM ": SgHunks    @ %p(%08x), sz=%d\n",
+				 hd->SgHunks, hd->SgHunksDMA, sz));
+
+			hd->qtag_tick = jiffies;
+
+			this->sh = sh;
+			mpt_scsi_hosts++;
+		}
+		this = mpt_adapter_find_next(this);
+	}
+
+	return mpt_scsi_hosts;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+    static char *info_kbuf = NULL;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_release - Unregister SCSI host from linux scsi mid-layer
+ *	@host: Pointer to Scsi_Host structure
+ *
+ *	(linux Scsi_Host_Template.release routine)
+ *	This routine releases all resources associated with the SCSI host
+ *	adapter.
+ *
+ *	Returns 0 for success.
+ */
+int
+mptscsih_release(struct Scsi_Host *host)
+{
+	MPT_SCSI_HOST	*hd;
+#ifndef MPT_SCSI_USE_NEW_EH
+	unsigned long	 flags;
+
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	if (mpt_scsih_taskQ_bh_active) {
+		int count = 10 * HZ;
+
+		dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+
+		/* Zap the taskQ! */
+		Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
+		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+		while(mpt_scsih_taskQ_bh_active && --count) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		if (!count)
+			printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n");
+	}
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+	hd = (MPT_SCSI_HOST *) host->hostdata;
+	if (hd != NULL) {
+		int sz1, sz2;
+
+		sz1 = sz2 = 0;
+		if (hd->ScsiLookup != NULL) {
+			sz1 = hd->ioc->req_depth * sizeof(void *);
+			kfree(hd->ScsiLookup);
+			hd->ScsiLookup = NULL;
+		}
+
+		if (hd->SgHunks != NULL) {
+
+			sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
+			pci_free_consistent(hd->ioc->pcidev, sz2,
+					    hd->SgHunks, hd->SgHunksDMA);
+			hd->SgHunks = NULL;
+		}
+		dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2));
+	}
+
+	if (mpt_scsi_hosts) {
+		if (--mpt_scsi_hosts == 0) {
+#if 0
+			mptscsih_flush_pending();
+#endif
+			mpt_event_deregister(ScsiDoneCtx);
+			dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+
+			mpt_deregister(ScsiDoneCtx);
+			mpt_deregister(ScsiTaskCtx);
+
+			if (info_kbuf != NULL)
+				kfree(info_kbuf);
+		}
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_info - Return information about MPT adapter
+ *	@SChost: Pointer to Scsi_Host structure
+ *
+ *	(linux Scsi_Host_Template.info routine)
+ *
+ *	Returns pointer to buffer where information was written.
+ */
+const char *
+mptscsih_info(struct Scsi_Host *SChost)
+{
+	MPT_SCSI_HOST *h;
+	int size = 0;
+
+	if (info_kbuf == NULL)
+		if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+			return info_kbuf;
+
+	h = (MPT_SCSI_HOST *)SChost->hostdata;
+	info_kbuf[0] = '\0';
+	mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0);
+	info_kbuf[size-1] = '\0';
+
+	return info_kbuf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+	static int max_qd = 1;
+#ifdef MPT_DEBUG
+	static int max_sges = 0;
+	static int max_xfer = 0;
+#endif
+#if 0
+	static int max_num_sges = 0;
+	static int max_sgent_len = 0;
+#endif
+#if 0
+static int index_log[128];
+static int index_ent = 0;
+static __inline__ void ADD_INDEX_LOG(int req_ent)
+{
+	int i = index_ent++;
+
+	index_log[i & (128 - 1)] = req_ent;
+}
+#else
+#define ADD_INDEX_LOG(req_ent)	do { } while(0)
+#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
+ *	@SCpnt: Pointer to Scsi_Cmnd structure
+ *	@done: Pointer SCSI mid-layer IO completion function
+ *
+ *	(linux Scsi_Host_Template.queuecommand routine)
+ *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
+ *	from a linux Scsi_Cmnd request and send it to the IOC.
+ *
+ *	Returns 0. (rtn value discarded by linux scsi mid-layer)
+ */
+int
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	struct Scsi_Host	*host;
+	MPT_SCSI_HOST		*hd;
+	MPT_FRAME_HDR		*mf;
+	SCSIIORequest_t		*pScsiReq;
+	int	 datadir;
+	u32	 len;
+	u32	 sgdir;
+	u32	 scsictl;
+	u32	 scsidir;
+	u32	 qtag;
+	u32	*mptr;
+	int	 sge_spill1;
+	int	 frm_sz;
+	int	 sges_left;
+	u32	 chain_offset;
+	int	 my_idx;
+	int	 i;
+
+	dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n",
+		    SCpnt, done));
+
+	host = SCpnt->host;
+	hd = (MPT_SCSI_HOST *) host->hostdata;
+	
+#if 0
+	if (host->host_busy >= 60) {
+		MPT_ADAPTER *ioc = hd->ioc;
+		u16 pci_command, pci_status;
+
+		/* The IOC is probably hung, investigate status. */
+		printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n",
+		       readl(&ioc->chip.fc9xx->DoorbellValue),
+		       readl(&ioc->chip.fc9xx->IntStatus),
+		       readl(&ioc->chip.fc9xx->ReplyFifo));
+		pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command);
+		pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status);
+		printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status);
+		{
+			/* DUMP req index logger. */
+			int begin, end;
+
+			begin = (index_ent - 65) & (128 - 1);
+			end = index_ent & (128 - 1);
+			printk("MPI: REQ_INDEX_HIST[");
+			while (begin != end) {
+				printk("(%04x)", index_log[begin]);
+				begin = (begin + 1) & (128 - 1);
+			}
+			printk("\n");
+		}
+		sti();
+		while(1)
+			barrier();
+	}
+#endif
+
+	SCpnt->scsi_done = done;
+
+	/* 20000617 -sralston
+	 *  GRRRRR...  Shouldn't have to do this but...
+	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
+	 *  If yes, return cached SenseData.
+	 */
+#ifdef MPT_SCSI_CACHE_AUTOSENSE
+	{
+		MPT_SCSI_DEV	*mpt_sdev;
+
+		mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata;
+		if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) {
+			u8 *dest = NULL;
+
+			if (!SCpnt->use_sg)
+				dest = SCpnt->request_buffer;
+			else {
+				struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+				if (sg)
+					dest = (u8 *) (unsigned long)sg_dma_address(sg);
+			}
+
+			if (dest && mpt_sdev->sense_sz) {
+				memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz);
+#ifdef MPT_DEBUG
+				{
+					int  i;
+					u8  *sb;
+
+					sb = mpt_sdev->CachedSense.data;
+					if (sb && ((sb[0] & 0x70) == 0x70)) {
+						printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n");
+						printk(KERN_WARNING " ");
+						for (i = 0; i < (8 + sb[7]); i++)
+							printk("%s%02x", i == 13 ? "-" : " ", sb[i]);
+						printk("\n");
+					}
+				}
+#endif
+			}
+			SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
+			SCpnt->result = 0;
+/*			spin_lock(&io_request_lock);	*/
+			SCpnt->scsi_done(SCpnt);
+/*			spin_unlock(&io_request_lock);	*/
+			return 0;
+		}
+	}
+#endif
+
+	if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
+		SCpnt->result = STS_BUSY;
+		SCpnt->scsi_done(SCpnt);
+/*		return 1;				*/
+		return 0;
+	}
+	pScsiReq = (SCSIIORequest_t *) mf;
+
+	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+	ADD_INDEX_LOG(my_idx);
+
+	/* Map the data portion, if any. */
+	sges_left = SCpnt->use_sg;
+	if (sges_left) {
+		sges_left = pci_map_sg(hd->ioc->pcidev,
+				       (struct scatterlist *) SCpnt->request_buffer,
+				       sges_left,
+				       scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	} else if (SCpnt->request_bufflen) {
+		dma_addr_t buf_dma_addr;
+
+		buf_dma_addr = pci_map_single(hd->ioc->pcidev,
+					      SCpnt->request_buffer,
+					      SCpnt->request_bufflen,
+					      scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+
+		/* We hide it here for later unmap. */
+		SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr;
+	}
+
+	/*
+	 *  Put together a MPT SCSI request...
+	 */
+
+	/* Assume SimpleQ, NO DATA XFER for now */
+
+	len = SCpnt->request_bufflen;
+	sgdir = 0x00000000;		/* SGL IN  (host<--ioc) */
+	scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+
+	/*
+	 *  The scsi layer should be handling this stuff
+	 *  (In 2.3.x it does -DaveM)
+	 */
+
+	/*  BUG FIX!  19991030 -sralston
+	 *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+	 *    Seems we may receive a buffer (len>0) even when there
+	 *    will be no data transfer!  GRRRRR...
+	 */
+	datadir = mptscsih_io_direction(SCpnt);
+	if (datadir < 0) {
+		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
+	} else if (datadir > 0) {
+		sgdir	= 0x04000000;			/* SGL OUT  (host-->ioc) */
+		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
+	} else {
+		len = 0;
+	}
+
+	qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+
+	/*
+	 *  Attach tags to the devices
+	 */
+	if (SCpnt->device->tagged_supported) {
+		/*
+		 *  Some drives are too stupid to handle fairness issues
+		 *  with tagged queueing. We throw in the odd ordered
+		 *  tag to stop them starving themselves.
+		 */
+		if ((jiffies - hd->qtag_tick) > (5*HZ)) {
+			qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+			hd->qtag_tick = jiffies;
+
+#if 0
+			/* These are ALWAYS zero!
+			 * (Because this is a place for the device driver to dynamically
+			 *  assign tag numbers any way it sees fit.  That's why -DaveM)
+			 */
+			dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n",
+					SCpnt->device->current_tag));
+			dprintk((KERN_DEBUG MYNAM ": sc->tag                 = %08x\n",
+					SCpnt->tag));
+#endif
+		}
+#if 0
+		else {
+			/* Hmmm...  I always see value of 0 here,
+			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
+			 * (Because this is a place for the device driver to dynamically
+			 *  assign tag numbers any way it sees fit.  That's why -DaveM)
+			 *
+			 * if (SCpnt->tag == HEAD_OF_QUEUE_TAG)
+			 */
+			if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG)
+				qtag = MPI_SCSIIO_CONTROL_HEADOFQ;
+			else if (SCpnt->tag == ORDERED_QUEUE_TAG)
+				qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+		}
+#endif
+	}
+
+	scsictl = scsidir | qtag;
+
+	frm_sz = hd->ioc->req_sz;
+
+	/* Ack!
+	 * sge_spill1 = 9;
+	 */
+	sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8;
+	/*  spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9
+	 *  spill1: for req_sz ==  96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5
+	 */
+	dsgprintk((KERN_INFO MYNAM ": SG: %x     spill1 = %d\n",
+		   my_idx, sge_spill1));
+
+#ifdef MPT_DEBUG
+	if (sges_left > max_sges) {
+		max_sges = sges_left;
+		dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges));
+	}
+#endif
+#if 0
+	if (sges_left > max_num_sges) {
+		max_num_sges = sges_left;
+		printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges);
+	}
+#endif
+
+	dsgprintk((KERN_INFO MYNAM ": SG: %x     sges_left = %d (initially)\n",
+		   my_idx, sges_left));
+
+	chain_offset = 0;
+	if (sges_left > (sge_spill1+1)) {
+#if 0
+		chain_offset = 0x1E;
+#endif
+		chain_offset = (frm_sz - 8) / 4;
+	}
+
+	pScsiReq->TargetID = SCpnt->target;
+	pScsiReq->Bus = hd->port;
+	pScsiReq->ChainOffset = chain_offset;
+	pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+	pScsiReq->CDBLength = SCpnt->cmd_len;
+
+/* We have 256 bytes alloc'd per IO; let's use it. */
+/*	pScsiReq->SenseBufferLength = SNS_LEN(SCpnt);	*/
+	pScsiReq->SenseBufferLength = 255;
+
+	pScsiReq->Reserved = 0;
+	pScsiReq->MsgFlags = 0;
+	pScsiReq->LUN[0] = 0;
+	pScsiReq->LUN[1] = SCpnt->lun;
+	pScsiReq->LUN[2] = 0;
+	pScsiReq->LUN[3] = 0;
+	pScsiReq->LUN[4] = 0;
+	pScsiReq->LUN[5] = 0;
+	pScsiReq->LUN[6] = 0;
+	pScsiReq->LUN[7] = 0;
+	pScsiReq->Control = cpu_to_le32(scsictl);
+
+	/*
+	 *  Write SCSI CDB into the message
+	 */
+	for (i = 0; i < 12; i++)
+		pScsiReq->CDB[i] = SCpnt->cmnd[i];
+	for (i = 12; i < 16; i++)
+		pScsiReq->CDB[i] = 0;
+
+	/* DataLength */
+	pScsiReq->DataLength = cpu_to_le32(len);
+
+	/* SenseBuffer low address */
+	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256));
+
+	mptr = (u32 *) &pScsiReq->SGL;
+
+	/*
+	 *  Now fill in the SGList...
+	 *  NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's
+	 *  in the remaining request frame.  We -could- do unlimited chains
+	 *  but each chain buffer can only be req_sz bytes in size, and
+	 *  we lose one SGE whenever we chain.
+	 *  For 128 req_sz, we can hold up to 16 SGE's per chain buffer.
+	 *  For practical reasons, limit ourselves to 1 overflow chain buffer;
+	 *  giving us 9 + 16 == 25 SGE's max.
+	 *  At 4 Kb per SGE, that yields 100 Kb max transfer.
+	 *
+	 *  (This code needs to be completely changed when/if 64-bit DMA
+	 *   addressing is used, since we will be able to fit much less than
+	 *   10 embedded SG entries. -DaveM)
+	 */
+	if (sges_left) {
+		struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+		u32  v1, v2;
+		int  sge_spill2;
+		int  sge_cur_spill;
+		int  sgCnt;
+		u8  *pSgBucket;
+		int  chain_sz;
+
+		len = 0;
+
+		/*	sge_spill2 = 15;
+		 *  spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15
+		 *  spill2: for req_sz ==  96 ( 96/8==12 SGEs max, first time!), --> use 11
+		 */
+		sge_spill2 = frm_sz / 8 - 1;
+		dsgprintk((KERN_INFO MYNAM ": SG: %x     spill2 = %d\n",
+			   my_idx, sge_spill2));
+
+		pSgBucket = NULL;
+		sgCnt = 0;
+		sge_cur_spill = sge_spill1;
+		while (sges_left) {
+#if 0
+			if (sg_dma_len(sg) > max_sgent_len) {
+				max_sgent_len = sg_dma_len(sg);
+				printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len);
+			}
+#endif
+			/* Write one simple SGE */
+			v1 = sgdir | 0x10000000 | sg_dma_len(sg);
+			len += sg_dma_len(sg);
+			v2 = sg_dma_address(sg);
+			dsgprintk((KERN_INFO MYNAM ": SG: %x     Writing SGE @%p: %08x %08x, sges_left=%d\n",
+				   my_idx, mptr, v1, v2, sges_left));
+			*mptr++ = cpu_to_le32(v1);
+			*mptr++ = cpu_to_le32(v2);
+			sg++;
+			sgCnt++;
+
+			if (--sges_left == 0) {
+				/* re-write 1st word of previous SGE with SIMPLE,
+				 * LE, EOB, and EOL bits!
+				 */
+				v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1);
+				dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n",
+					   my_idx, mptr-2, v1));
+				*(mptr - 2) = cpu_to_le32(v1);
+			} else {
+				if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) {
+					dsgprintk((KERN_INFO MYNAM ": SG: %x     SG spill at modulo 0!\n",
+						   my_idx));
+
+					/* Fixup previous SGE with LE bit! */
+					v1 = sgdir | 0x90000000 | sg_dma_len(sg-1);
+					dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n",
+						   my_idx, mptr-2, v1));
+					*(mptr - 2) = cpu_to_le32(v1);
+
+					chain_offset = 0;
+					/* Going to need another chain? */
+					if (sges_left > (sge_spill2+1)) {
+#if 0
+						chain_offset = 0x1E;
+#endif
+						chain_offset = (frm_sz - 8) / 4;
+						chain_sz = frm_sz;
+					} else {
+						chain_sz = sges_left * 8;
+					}
+
+					/* write chain SGE at mptr. */
+					v1 = 0x30000000 | chain_offset<<16 | chain_sz;
+					if (pSgBucket == NULL) {
+						pSgBucket = hd->SgHunks
+							+ (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK);
+					} else {
+						pSgBucket += frm_sz;
+					}
+					v2 = (hd->SgHunksDMA +
+					      ((u8 *)pSgBucket - (u8 *)hd->SgHunks));
+					dsgprintk((KERN_INFO MYNAM ": SG: %x     Writing SGE @%p: %08x %08x (CHAIN!)\n",
+						   my_idx, mptr, v1, v2));
+					*(mptr++) = cpu_to_le32(v1);
+					*(mptr) = cpu_to_le32(v2);
+
+					mptr = (u32 *) pSgBucket;
+					sgCnt = 0;
+					sge_cur_spill = sge_spill2;
+				}
+			}
+		}
+	} else {
+		dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n",
+			   SCpnt, SCpnt->request_bufflen));
+
+		if (len > 0) {
+			dma_addr_t buf_dma_addr;
+
+			buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr;
+			*(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen);
+			*(mptr++) = cpu_to_le32(buf_dma_addr);
+		}
+	}
+
+#ifdef MPT_DEBUG
+	/* if (SCpnt->request_bufflen > max_xfer) */
+	if (len > max_xfer) {
+		max_xfer = len;
+		dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer));
+	}
+#endif
+
+	hd->ScsiLookup[my_idx] = SCpnt;
+
+	/* Main banana... */
+	mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+
+	atomic_inc(&queue_depth);
+	if (atomic_read(&queue_depth) > max_qd) {
+		max_qd = atomic_read(&queue_depth);
+		dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
+	}
+
+	mb();
+	dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt));
+
+	return 0;
+}
+
+#ifdef MPT_SCSI_USE_NEW_EH		/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    mptscsih_abort
+    Returns: 0=SUCCESS, else FAILED
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *	(linux Scsi_Host_Template.eh_abort_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.  
+ */
+int
+mptscsih_abort(Scsi_Cmnd * SCpnt)
+{
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	MPT_SCSI_HOST	*hd;
+	u32		*msg;
+	u32		 ctx2abort;
+	int		 i;
+
+	printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
+		SCpnt->result = STS_BUSY;
+		SCpnt->scsi_done(SCpnt);
+		return FAILED;
+	}
+
+	pScsiTm = (SCSITaskMgmt_t *) mf;
+	msg = (u32 *) mf;
+
+	pScsiTm->TargetID = SCpnt->target;
+	pScsiTm->Bus = hd->port;
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+	pScsiTm->Reserved = 0;
+	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->MsgFlags = 0;
+
+	for (i = 0; i < 8; i++) {
+		u8 val = 0;
+		if (i == 1)
+			val = SCpnt->lun;
+		pScsiTm->LUN[i] = val;
+	}
+
+	for (i = 0; i < 7; i++)
+		pScsiTm->Reserved2[i] = 0;
+
+	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+	 * (the IO to be ABORT'd)
+	 *
+	 * NOTE: Since we do not byteswap MsgContext, we do not
+	 *	 swap it here either.  It is an opaque cookie to
+	 *	 the controller, so it does not matter. -DaveM
+	 */
+	ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
+	dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
+	pScsiTm->TaskMsgContext = ctx2abort;
+
+	wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+	mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME!  Check return status! */
+	(void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+	wmb();
+
+	return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *	(linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+{
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	MPT_SCSI_HOST	*hd;
+	u32		*msg;
+	int		 i;
+
+	printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
+		SCpnt->result = STS_BUSY;
+		SCpnt->scsi_done(SCpnt);
+		return FAILED;
+	}
+
+	pScsiTm = (SCSITaskMgmt_t *) mf;
+	msg = (u32 *) mf;
+
+	pScsiTm->TargetID = SCpnt->target;
+	pScsiTm->Bus = hd->port;
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+	pScsiTm->Reserved = 0;
+	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->MsgFlags = 0;
+
+	for (i = 0; i < 8; i++)
+		pScsiTm->LUN[i] = 0;
+
+	/* Control: No data direction, set task mgmt bit? */
+	for (i = 0; i < 7; i++)
+		pScsiTm->Reserved2[i] = 0;
+
+	pScsiTm->TaskMsgContext = cpu_to_le32(0);
+
+	wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+	mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME!  Check return status! */
+	(void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+	wmb();
+
+	return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *	(linux Scsi_Host_Template.eh_dev_reset_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
+{
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	MPT_SCSI_HOST	*hd;
+	u32		*msg;
+	int		 i;
+
+	printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
+		SCpnt->result = STS_BUSY;
+		SCpnt->scsi_done(SCpnt);
+		return FAILED;
+	}
+
+	pScsiTm = (SCSITaskMgmt_t *) mf;
+	msg = (u32*)mf;
+
+	pScsiTm->TargetID = SCpnt->target;
+	pScsiTm->Bus = hd->port;
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+	pScsiTm->Reserved = 0;
+	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->MsgFlags = 0;
+
+	/* _TARGET_RESET goes to LUN 0 always! */
+	for (i = 0; i < 8; i++)
+		pScsiTm->LUN[i] = 0;
+
+	/* Control: No data direction, set task mgmt bit? */
+	for (i = 0; i < 7; i++)
+		pScsiTm->Reserved2[i] = 0;
+
+	pScsiTm->TaskMsgContext = cpu_to_le32(0);
+
+	wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+	mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME!  Check return status! */
+	(void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+	wmb();
+
+	return SUCCESS;
+}
+
+#if 0	/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_host_reset - Perform a SCSI host adapter RESET!
+ *	new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *	(linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_host_reset(Scsi_Cmnd * SCpnt)
+{
+	return FAILED;
+}
+#endif	/* } */
+
+#else		/* MPT_SCSI old EH stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_old_abort - Abort linux Scsi_Cmnd routine
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *	(linux Scsi_Host_Template.abort routine)
+ *
+ *	Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ */
+int
+mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+{
+	MPT_SCSI_HOST		*hd;
+	MPT_FRAME_HDR		*mf;
+	struct tq_struct	*ptaskfoo;
+	unsigned long		 flags;
+
+	printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_ABORT << 16;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_ABORT_SUCCESS;
+	}
+
+	/*
+	 *  Check to see if there's already an ABORT queued for this guy.
+	 */
+	mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+	if (mf != NULL) {
+		return SCSI_ABORT_PENDING;
+	}
+
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
+		SCpnt->result = STS_BUSY;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_ABORT_BUSY;
+	}
+
+	/*
+	 *  Add ourselves to (end of) mpt_scsih_taskQ.
+	 *  Check to see if our _bh is running.  If NOT, schedule it.
+	 */
+	dslprintk((KERN_INFO MYNAM ": spinlock#2\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+	mpt_scsih_taskQ_cnt++;
+	/* Yikes - linkage! */
+/*	SCpnt->host_scribble = (unsigned char *)mf;	*/
+	mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+	mf->u.frame.linkage.argp1 = SCpnt;
+	if (! mpt_scsih_taskQ_bh_active) {
+		mpt_scsih_taskQ_bh_active = 1;
+		/*
+		 *  Oh how cute, no alloc/free/mgmt needed if we use
+		 *  (bottom/unused portion of) MPT request frame.
+		 */
+		ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
+		ptaskfoo->sync = 0;
+		ptaskfoo->routine = mptscsih_taskmgmt_bh;
+		ptaskfoo->data = SCpnt;
+
+		SCHEDULE_TASK(ptaskfoo);
+	}
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+	return SCSI_ABORT_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_old_reset - Perform a SCSI BUS_RESET!
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *	@reset_flags: (not used?)
+ *
+ *	(linux Scsi_Host_Template.reset routine)
+ *
+ *	Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
+ */
+int
+mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+	MPT_SCSI_HOST		*hd;
+	MPT_FRAME_HDR		*mf;
+	struct tq_struct	*ptaskfoo;
+	unsigned long		 flags;
+
+	printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_RESET << 16;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_RESET_SUCCESS;
+	}
+
+	/*
+	 *  Check to see if there's already a BUS_RESET queued for this guy.
+	 */
+	mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
+	if (mf != NULL) {
+		return SCSI_RESET_PENDING;
+	}
+
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
+		SCpnt->result = STS_BUSY;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_RESET_PUNT;
+	}
+
+	/*
+	 *  Add ourselves to (end of) mpt_scsih_taskQ.
+	 *  Check to see if our _bh is running.  If NOT, schedule it.
+	 */
+	dslprintk((KERN_INFO MYNAM ": spinlock#3\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+	mpt_scsih_taskQ_cnt++;
+	/* Yikes - linkage! */
+/*	SCpnt->host_scribble = (unsigned char *)mf;	*/
+	mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	mf->u.frame.linkage.argp1 = SCpnt;
+	if (! mpt_scsih_taskQ_bh_active) {
+		mpt_scsih_taskQ_bh_active = 1;
+		/*
+		 *  Oh how cute, no alloc/free/mgmt needed if we use
+		 *  (bottom/unused portion of) MPT request frame.
+		 */
+		ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
+		ptaskfoo->sync = 0;
+		ptaskfoo->routine = mptscsih_taskmgmt_bh;
+		ptaskfoo->data = SCpnt;
+
+		SCHEDULE_TASK(ptaskfoo);
+	}
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+	return SCSI_RESET_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
+ *	@sc: (unused)
+ *
+ *	This routine (thread) is active whenever there are any outstanding
+ *	SCSI task management requests for a SCSI host adapter.
+ *	IMPORTANT!  This routine is scheduled therefore should never be
+ *	running in ISR context.  i.e., it's safe to sleep here.
+ */
+void
+mptscsih_taskmgmt_bh(void *sc)
+{
+	Scsi_Cmnd	*SCpnt;
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	MPT_SCSI_HOST	*hd;
+	u32		 ctx2abort = 0;
+	int		 i;
+	unsigned long	 flags;
+	u8		 task_type;
+
+	dslprintk((KERN_INFO MYNAM ": spinlock#4\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	mpt_scsih_taskQ_bh_active = 1;
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+	while (1) {
+		/*
+		 *  We MUST remove item from taskQ *before* we format the
+		 *  frame as a SCSITaskMgmt request and send it down to the IOC.
+		 */
+		dslprintk((KERN_INFO MYNAM ": spinlock#5\n"));
+		spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+		if (Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+			spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+			break;
+		}
+		mf = mpt_scsih_taskQ.head;
+		Q_DEL_ITEM(&mf->u.frame.linkage);
+		mpt_scsih_taskQ_cnt--;
+		mpt_scsih_active_taskmgmt_mf = mf;
+		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+		SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
+		if (SCpnt == NULL) {
+			printk(KERN_ERR MYNAM ": ERROR: TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt);
+			continue;
+		}
+		pScsiTm = (SCSITaskMgmt_t *) mf;
+
+		for (i = 0; i < 8; i++) {
+			pScsiTm->LUN[i] = 0;
+		}
+
+		task_type = mf->u.frame.linkage.arg1;
+		if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+		{
+			printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf:sc=%p:%p)\n", mf, SCpnt);
+
+			/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+			 * (the IO to be ABORT'd)
+			 *
+			 * NOTE: Since we do not byteswap MsgContext, we do not
+			 *	 swap it here either.  It is an opaque cookie to
+			 *	 the controller, so it does not matter. -DaveM
+			 */
+			ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
+			pScsiTm->LUN[1] = SCpnt->lun;
+		}
+		else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+		{
+			printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf:sc=%p:%p)\n", mf, SCpnt);
+		}
+#if 0
+		else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {}
+		else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {}
+#endif
+
+		printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+		hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+		pScsiTm->TargetID = SCpnt->target;
+		pScsiTm->Bus = hd->port;
+		pScsiTm->ChainOffset = 0;
+		pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+		pScsiTm->Reserved = 0;
+		pScsiTm->TaskType = task_type;
+		pScsiTm->Reserved1 = 0;
+		pScsiTm->MsgFlags = 0;
+
+		for (i = 0; i < 7; i++)
+			pScsiTm->Reserved2[i] = 0;
+
+		dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
+		pScsiTm->TaskMsgContext = ctx2abort;
+
+		/* Control: No data direction, set task mgmt bit? */
+
+		/*
+		 *  As of MPI v0.10 this request can NOT be sent (normally)
+		 *  via FIFOs.	So we can't:
+		 *		mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+		 *  SCSITaskMgmt requests MUST be sent ONLY via
+		 *  Doorbell/handshake now.   :-(
+		 *
+		 *  FIXME!  Check return status!
+		 */
+		(void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), (u32*)mf);
+
+		/* Spin-Wait for TaskMgmt complete!!! */
+		while (mpt_scsih_active_taskmgmt_mf != NULL) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ/2);
+		}
+	}
+
+	dslprintk((KERN_INFO MYNAM ": spinlock#6\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	mpt_scsih_taskQ_bh_active = 0;
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+	return;
+}
+
+#endif		/* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_taskmgmt_complete - Callback routine, gets registered to
+ *	Fusion MPT base	driver
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mf: Pointer to SCSI task mgmt request frame
+ *	@r: Pointer to SCSI task mgmt reply frame
+ *
+ *	This routine is called from mptbase.c::mpt_interrupt() at the completion
+ *	of any SCSI task management request.
+ *	This routine is registered with the MPT (base) driver at driver
+ *	load/init time via the mpt_register() API call.
+ *
+ *	Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+{
+	SCSITaskMgmtReply_t	*pScsiTmReply;
+	SCSITaskMgmt_t		*pScsiTmReq;
+	u8			 tmType;
+#ifndef MPT_SCSI_USE_NEW_EH
+	unsigned long		 flags;
+#endif
+
+	dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n",
+		 mf, r));
+
+#ifndef MPT_SCSI_USE_NEW_EH
+	dslprintk((KERN_INFO MYNAM ": spinlock#7\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	/* It better be the active one! */
+	if (mf != mpt_scsih_active_taskmgmt_mf) {
+		printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf);
+		mpt_scsih_active_taskmgmt_mf = NULL;
+		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+		return 1;
+	}
+
+#ifdef MPT_DEBUG
+	if ((mf == NULL) ||
+	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+		printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf);
+		mpt_scsih_active_taskmgmt_mf = NULL;
+		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+		return 1;
+	}
+#endif
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+	if (r != NULL) {
+		pScsiTmReply = (SCSITaskMgmtReply_t*)r;
+		pScsiTmReq = (SCSITaskMgmt_t*)mf;
+
+		/* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
+		tmType = pScsiTmReq->TaskType;
+
+		dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType));
+		dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n",
+			 le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+		/* Error?  (anything non-zero?) */
+		if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
+			dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType));
+			dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n",
+				 le16_to_cpu(pScsiTmReply->IOCStatus)));
+			dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n",
+				 le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+		} else {
+			dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType));
+		}
+	}
+
+#ifndef MPT_SCSI_USE_NEW_EH
+	/*
+	 *  Signal to _bh thread that we finished.
+	 */
+	dslprintk((KERN_INFO MYNAM ": spinlock#8\n"));
+	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+	mpt_scsih_active_taskmgmt_mf = NULL;
+	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+	return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	This is anyones guess quite frankly.
+ */
+
+int
+mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+	int size;
+
+	size = disk->capacity;
+	ip[0] = 64;				/* heads			*/
+	ip[1] = 32;				/* sectors			*/
+	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
+		ip[0] = 255;			/* heads			*/
+		ip[1] = 63;			/* sectors			*/
+		ip[2] = size / (255 * 63);	/* cylinders			*/
+	}
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ *  Return absolute SCSI data direction:
+ *     1 = _DATA_OUT
+ *     0 = _DIR_NONE
+ *    -1 = _DATA_IN
+ */
+static int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) {
+	/*  _DATA_OUT commands	*/
+	case WRITE_6:		case WRITE_10:		case WRITE_12:
+	case WRITE_LONG:	case WRITE_SAME:	case WRITE_BUFFER:
+	case WRITE_VERIFY:	case WRITE_VERIFY_12:
+	case COMPARE:		case COPY:		case COPY_VERIFY:
+	case SEARCH_EQUAL:	case SEARCH_HIGH:	case SEARCH_LOW:
+	case SEARCH_EQUAL_12:	case SEARCH_HIGH_12:	case SEARCH_LOW_12:
+	case MODE_SELECT:	case MODE_SELECT_10:	case LOG_SELECT:
+	case SEND_DIAGNOSTIC:	case CHANGE_DEFINITION: case UPDATE_BLOCK:
+	case SET_WINDOW:	case MEDIUM_SCAN:	case SEND_VOLUME_TAG:
+	case REASSIGN_BLOCKS:
+	case PERSISTENT_RESERVE_OUT:
+	case 0xea:
+		return 1;
+
+	/*  No data transfer commands  */
+	case SEEK_6:		case SEEK_10:
+	case RESERVE:		case RELEASE:
+	case TEST_UNIT_READY:
+	case START_STOP:
+	case ALLOW_MEDIUM_REMOVAL:
+		return 0;
+
+	/*  Conditional data transfer commands	*/
+	case FORMAT_UNIT:
+		if (cmd->cmnd[1] & 0x10)	/* FmtData (data out phase)? */
+			return 1;
+		else
+			return 0;
+
+	case VERIFY:
+		if (cmd->cmnd[1] & 0x02)	/* VERIFY:BYTCHK (data out phase)? */
+			return 1;
+		else
+			return 0;
+
+	case RESERVE_10:
+		if (cmd->cmnd[1] & 0x03)	/* RESERSE:{LongID|Extent} (data out phase)? */
+			return 1;
+		else
+			return 0;
+
+#if 0
+	case REZERO_UNIT:	/* (or REWIND) */
+	case SPACE:
+	case ERASE:		case ERASE_10:
+	case SYNCHRONIZE_CACHE:
+	case LOCK_UNLOCK_CACHE:
+#endif
+
+	/*  Must be data _IN!  */
+	default:
+		return -1;
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+{
+	MPT_SCSI_DEV	*mpt_sdev = NULL;
+	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
+	char		 devFoo[32];
+	IO_Info_t	 thisIo;
+
+	if (sc && sc->device)
+		mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata;
+
+	if (sense_count) {
+		u8 *sense_data;
+		int req_index;
+
+		/* Copy the sense received into the scsi command block. */
+		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+		sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256));
+		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+		/* Cache SenseData for this SCSI device! */
+		if (mpt_sdev) {
+			memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count);
+			mpt_sdev->sense_sz = sense_count;
+		}
+	} else {
+		dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n"));
+	}
+
+
+	thisIo.cdbPtr = sc->cmnd;
+	thisIo.sensePtr = sc->sense_buffer;
+	thisIo.SCSIStatus = pScsiReply->SCSIStatus;
+	thisIo.DoDisplay = 1;
+	sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun);
+	thisIo.DevIDStr = devFoo;
+/* fubar */
+	thisIo.dataPtr = NULL;
+	thisIo.inqPtr = NULL;
+	if (sc->device) {
+		thisIo.inqPtr = sc->device->vendor-8;		/* FIXME!!! */
+	}
+	(void) mpt_ScsiHost_ErrorReport(&thisIo);
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static u32
+SCPNT_TO_MSGCTX(Scsi_Cmnd *sc)
+{
+	MPT_SCSI_HOST *hd;
+	MPT_FRAME_HDR *mf;
+	int i;
+
+	hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+
+	for (i = 0; i < hd->ioc->req_depth; i++) {
+		if (hd->ScsiLookup[i] == sc) {
+			mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
+			return mf->u.frame.hwhdr.msgctxu.MsgContext;
+		}
+	}
+
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* see mptscsih.h */
+
+#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+	static Scsi_Host_Template driver_template = MPT_SCSIHOST;
+#	include "../../scsi/scsi_module.c"
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+	dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event));
+
+	switch (event) {
+	case MPI_EVENT_UNIT_ATTENTION:			/* 03 */
+		/* FIXME! */
+		break;
+	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
+		/* FIXME! */
+		break;
+	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
+		/* FIXME! */
+		break;
+	case MPI_EVENT_LOGOUT:				/* 09 */
+		/* FIXME! */
+		break;
+
+		/*
+		 *  CHECKME! Don't think we need to do
+		 *  anything for these, but...
+		 */
+	case MPI_EVENT_RESCAN:				/* 06 */
+	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
+	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
+		/*
+		 *  CHECKME!  Falling thru...
+		 */
+
+	case MPI_EVENT_NONE:				/* 00 */
+	case MPI_EVENT_LOG_DATA:			/* 01 */
+	case MPI_EVENT_STATE_CHANGE:			/* 02 */
+	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
+	default:
+		dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event));
+		break;
+	}
+
+	return 1;		/* currently means nothing really */
+}
+
+#if 0		/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+ *
+ *	drivers/message/fusion/scsiherr.c
+ */
+
+//extern const char	**mpt_ScsiOpcodesPtr;	/* needed by mptscsih.c */
+//extern ASCQ_Table_t	 *mpt_ASCQ_TablePtr;
+//extern int		  mpt_ASCQ_TableSz;
+
+/*  Lie!  */
+#define MYNAM	"mptscsih"
+
+#endif		/* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* old symsense.c stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ * To protect ourselves against those that would pass us bogus pointers
+ */
+static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
+    = { 0x1F, 0x00, 0x00, 0x00,
+	0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
+    = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00 };
+static u8 dummyCDB[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummyScsiData[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#if 0
+static const char *PeripheralDeviceTypeString[32] = {
+	"Direct-access",		/* 00h */
+	"Sequential-access",		/* 01h */
+	"Printer",			/* 02h */
+	"Processor",			/* 03h */
+			/*"Write-Once-Read-Multiple",*/	/* 04h */
+	"WORM",				/* 04h */
+	"CD-ROM",			/* 05h */
+	"Scanner",			/* 06h */
+	"Optical memory",		/* 07h */
+	"Media Changer",		/* 08h */
+	"Communications",		/* 09h */
+	"(Graphics arts pre-press)",	/* 0Ah */
+	"(Graphics arts pre-press)",	/* 0Bh */
+	"Array controller",		/* 0Ch */
+	"Enclosure services",		/* 0Dh */
+	"Simplified direct-access",	/* 0Eh */
+	"Reserved-0Fh",			/* 0Fh */
+	"Reserved-10h",			/* 10h */
+	"Reserved-11h",			/* 11h */
+	"Reserved-12h",			/* 12h */
+	"Reserved-13h",			/* 13h */
+	"Reserved-14h",			/* 14h */
+	"Reserved-15h",			/* 15h */
+	"Reserved-16h",			/* 16h */
+	"Reserved-17h",			/* 17h */
+	"Reserved-18h",			/* 18h */
+	"Reserved-19h",			/* 19h */
+	"Reserved-1Ah",			/* 1Ah */
+	"Reserved-1Bh",			/* 1Bh */
+	"Reserved-1Ch",			/* 1Ch */
+	"Reserved-1Dh",			/* 1Dh */
+	"Reserved-1Eh",			/* 1Eh */
+	"Unknown"			/* 1Fh */
+};
+#endif
+
+static char *ScsiStatusString[] = {
+	"GOOD",					/* 00h */
+	NULL,					/* 01h */
+	"CHECK CONDITION",			/* 02h */
+	NULL,					/* 03h */
+	"CONDITION MET",			/* 04h */
+	NULL,					/* 05h */
+	NULL,					/* 06h */
+	NULL,					/* 07h */
+	"BUSY",					/* 08h */
+	NULL,					/* 09h */
+	NULL,					/* 0Ah */
+	NULL,					/* 0Bh */
+	NULL,					/* 0Ch */
+	NULL,					/* 0Dh */
+	NULL,					/* 0Eh */
+	NULL,					/* 0Fh */
+	"INTERMEDIATE",				/* 10h */
+	NULL,					/* 11h */
+	NULL,					/* 12h */
+	NULL,					/* 13h */
+	"INTERMEDIATE-CONDITION MET",		/* 14h */
+	NULL,					/* 15h */
+	NULL,					/* 16h */
+	NULL,					/* 17h */
+	"RESERVATION CONFLICT",			/* 18h */
+	NULL,					/* 19h */
+	NULL,					/* 1Ah */
+	NULL,					/* 1Bh */
+	NULL,					/* 1Ch */
+	NULL,					/* 1Dh */
+	NULL,					/* 1Eh */
+	NULL,					/* 1Fh */
+	NULL,					/* 20h */
+	NULL,					/* 21h */
+	"COMMAND TERMINATED",			/* 22h */
+	NULL,					/* 23h */
+	NULL,					/* 24h */
+	NULL,					/* 25h */
+	NULL,					/* 26h */
+	NULL,					/* 27h */
+	"TASK SET FULL",			/* 28h */
+	NULL,					/* 29h */
+	NULL,					/* 2Ah */
+	NULL,					/* 2Bh */
+	NULL,					/* 2Ch */
+	NULL,					/* 2Dh */
+	NULL,					/* 2Eh */
+	NULL,					/* 2Fh */
+	"ACA ACTIVE",				/* 30h */
+	NULL
+};
+
+static const char *ScsiCommonOpString[] = {
+	"TEST UNIT READY",			/* 00h */
+	"REZERO UNIT (REWIND)",			/* 01h */
+	NULL,					/* 02h */
+	"REQUEST_SENSE",			/* 03h */
+	"FORMAT UNIT (MEDIUM)",			/* 04h */
+	"READ BLOCK LIMITS",			/* 05h */
+	NULL,					/* 06h */
+	"REASSIGN BLOCKS",			/* 07h */
+	"READ(6)",				/* 08h */
+	NULL,					/* 09h */
+	"WRITE(6)",				/* 0Ah */
+	"SEEK(6)",				/* 0Bh */
+	NULL,					/* 0Ch */
+	NULL,					/* 0Dh */
+	NULL,					/* 0Eh */
+	"READ REVERSE",				/* 0Fh */
+	"WRITE_FILEMARKS",			/* 10h */
+	"SPACE(6)",				/* 11h */
+	"INQUIRY",				/* 12h */
+	NULL
+};
+
+static const char *SenseKeyString[] = {
+	"NO SENSE",				/* 0h */
+	"RECOVERED ERROR",			/* 1h */
+	"NOT READY",				/* 2h */
+	"MEDIUM ERROR",				/* 3h */
+	"HARDWARE ERROR",			/* 4h */
+	"ILLEGAL REQUEST",			/* 5h */
+	"UNIT ATTENTION",			/* 6h */
+	"DATA PROTECT",				/* 7h */
+	"BLANK CHECK",				/* 8h */
+	"VENDOR-SPECIFIC",			/* 9h */
+	"ABORTED COPY",				/* Ah */
+	"ABORTED COMMAND",			/* Bh */
+	"EQUAL (obsolete)",			/* Ch */
+	"VOLUME OVERFLOW",			/* Dh */
+	"MISCOMPARE",				/* Eh */
+	"RESERVED",				/* Fh */
+	NULL
+};
+
+#define SPECIAL_ASCQ(c,q) \
+	(((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
+ *			   then print additional information via
+ *			   a call to SDMS_SystemAlert().
+ *
+ *  Return: nothing
+ */
+static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+{
+	u8	*sd;
+	u8	 BadValue;
+	u8	 SenseKey;
+	int	 Offset;
+	int	 len = strlen(msg1);
+
+	sd = ioop->sensePtr;
+	if (SD_Additional_Sense_Length(sd) < 8)
+		return;
+
+	SenseKey = SD_Sense_Key(sd);
+
+	if (SD_Sense_Key_Specific_Valid(sd)) {
+		if (SenseKey == SK_ILLEGAL_REQUEST) {
+			Offset = SD_Bad_Byte(sd);
+			if (SD_Was_Illegal_Request(sd)) {
+				BadValue = ioop->cdbPtr[Offset];
+				len += sprintf(msg1+len, "\n  Illegal CDB value=%02Xh found at CDB ",
+						BadValue);
+		} else {
+			BadValue = ioop->dataPtr[Offset];
+			len += sprintf(msg1+len, "\n  Illegal DATA value=%02Xh found at DATA ",
+					BadValue);
+		}
+		len += sprintf(msg1+len, "byte=%02Xh", Offset);
+		if (SD_SKS_Bit_Pointer_Valid(sd))
+			len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
+		} else if ((SenseKey == SK_RECOVERED_ERROR) ||
+			   (SenseKey == SK_HARDWARE_ERROR) ||
+			   (SenseKey == SK_MEDIUM_ERROR)) {
+			len += sprintf(msg1+len, "\n  Recovery algorithm Actual_Retry_Count=%02Xh",
+			SD_Actual_Retry_Count(sd));
+		}
+	}
+}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_cdb(char *foo, unsigned char *cdb)
+{
+	int i, grpCode, cdbLen;
+	int l = 0;
+
+	grpCode = cdb[0] >> 5;
+	if (grpCode < 1)
+		cdbLen = 6;
+	else if (grpCode < 3)
+		cdbLen = 10;
+	else if (grpCode == 5)
+		cdbLen = 12;
+	else
+		cdbLen = 16;
+
+	for (i=0; i < cdbLen; i++)
+		l += sprintf(foo+l, " %02X", cdb[i]);
+
+	return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_sd(char *foo, unsigned char *sd)
+{
+	int snsLen = 8 + SD_Additional_Sense_Length(sd);
+	int l = 0;
+	int i;
+
+	for (i=0; i < MIN(snsLen,18); i++)
+		l += sprintf(foo+l, " %02X", sd[i]);
+	l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+
+	return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
+static const char * ascq_set_strings_4max(
+		u8 ASC, u8 ASCQ,
+		const char **s1, const char **s2, const char **s3, const char **s4)
+{
+	static const char *asc_04_part1_string = "LOGICAL UNIT ";
+	static const char *asc_04_part2a_string = "NOT READY, ";
+	static const char *asc_04_part2b_string = "IS ";
+	static const char *asc_04_ascq_NN_part3_strings[] = {	/* ASC ASCQ (hex) */
+	  "CAUSE NOT REPORTABLE",				/* 04 00 */
+	  "IN PROCESS OF BECOMING READY",			/* 04 01 */
+	  "INITIALIZING CMD. REQUIRED",				/* 04 02 */
+	  "MANUAL INTERVENTION REQUIRED",			/* 04 03 */
+	  /* Add	" IN PROGRESS" to all the following... */
+	  "FORMAT",						/* 04 04 */
+	  "REBUILD",						/* 04 05 */
+	  "RECALCULATION",					/* 04 06 */
+	  "OPERATION",						/* 04 07 */
+	  "LONG WRITE",						/* 04 08 */
+	  "SELF-TEST",						/* 04 09 */
+	  NULL
+	};
+	static char *asc_04_part4_string = " IN PROGRESS";
+
+	static char *asc_29_ascq_NN_strings[] = {		/* ASC ASCQ (hex) */
+	  "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",	/* 29 00 */
+	  "POWER ON OCCURRED",					/* 29 01 */
+	  "SCSI BUS RESET OCCURRED",				/* 29 02 */
+	  "BUS DEVICE RESET FUNCTION OCCURRED",			/* 29 03 */
+	  "DEVICE INTERNAL RESET",				/* 29 04 */
+	  "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED",		/* 29 05 */
+	  "TRANSCEIVER MODE CHANGED TO LVD",			/* 29 06 */
+	  NULL
+	};
+	static char *ascq_vendor_uniq = "(Vendor Unique)";
+	static char *ascq_noone = "(no matching ASC/ASCQ description found)";
+	int idx;
+
+	*s1 = *s2 = *s3 = *s4 = "";		/* set'em all to the empty "" string */
+
+	/* CHECKME! Need lock/sem?
+	 *  Update and examine for isense module presense.
+	 */
+	mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+
+	if (mptscsih_ASCQ_TablePtr == NULL) {
+		/* 2nd chances... */
+		if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
+			*s1 = asc_04_part1_string;
+			*s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
+			*s3 = asc_04_ascq_NN_part3_strings[ASCQ];
+			/* check for " IN PROGRESS" ones */
+			if (ASCQ >= 0x04)
+				*s4 = asc_04_part4_string;
+		} else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
+			*s1 = asc_29_ascq_NN_strings[ASCQ];
+		/*
+		 *	else { leave all *s[1-4] values pointing to the empty "" string }
+		 */
+		return *s1;
+	}
+
+	/*
+	 *  Need to check ASC here; if it is "special," then
+	 *  the ASCQ is variable, and indicates failed component number.
+	 *  We must treat the ASCQ as a "don't care" while searching the
+	 *  mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
+	 *  on when we actually need to identify the failed component.
+	 */
+	if (SPECIAL_ASCQ(ASC,ASCQ))
+		ASCQ = 0xFF;
+
+	/*  OK, now search mptscsih_ASCQ_Table[] for a matching entry  */
+	for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
+		if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ))
+			return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description);
+
+	if ((ASC >= 0x80) || (ASCQ >= 0x80))
+		*s1 = ascq_vendor_uniq;
+	else
+		*s1 = ascq_noone;
+
+	return *s1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Error Report; desired output format...
+ *---
+SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
+  SCSI_Status=02h (CHECK CONDITION)
+  Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
+  SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
+  SenseKey=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+ *---
+ */
+
+int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
+{
+	char		 foo[512];
+	char		 buf2[32];
+	char		*statstr;
+	const char	*opstr;
+	int		 sk		= SD_Sense_Key(ioop->sensePtr);
+	const char	*skstr		= SenseKeyString[sk];
+	unsigned char	 asc		= SD_ASC(ioop->sensePtr);
+	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
+	int		 l;
+
+	/*
+	 *  More quiet mode.
+	 *  Filter out common, repetitive, warning-type errors...  like:
+	 *    POWER ON (06,29/00 or 06,29/01),
+	 *    SPINNING UP (02,04/01),
+	 *    LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
+	 */
+	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
+	     || (sk==SK_NOT_READY	&& asc==0x04 && ascq==0x01)
+	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
+	   )
+	{
+		/* Do nothing! */
+		return 0;
+	}
+
+	/*
+	 *  Protect ourselves...
+	 */
+	if (ioop->cdbPtr == NULL)
+		ioop->cdbPtr = dummyCDB;
+	if (ioop->sensePtr == NULL)
+		ioop->sensePtr = dummySenseData;
+	if (ioop->inqPtr == NULL)
+		ioop->inqPtr = dummyInqData;
+	if (ioop->dataPtr == NULL)
+		ioop->dataPtr = dummyScsiData;
+
+	statstr = NULL;
+	if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
+	    ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
+		(void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
+		statstr = buf2;
+	}
+
+	opstr = NULL;
+	if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
+		opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
+	else if (mpt_ScsiOpcodesPtr)
+		opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
+
+	l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
+	  "  SCSI_Status=%02Xh (%s)\n"
+	  "  Original_CDB[]:",
+			ioop->DevIDStr,
+			ioop->SCSIStatus,
+			statstr);
+	l += dump_cdb(foo+l, ioop->cdbPtr);
+	if (opstr)
+		l += sprintf(foo+l, " - \"%s\"", opstr);
+	l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
+	l += dump_sd(foo+l, ioop->sensePtr);
+	l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
+			sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
+
+	{
+		const char	*x1, *x2, *x3, *x4;
+		x1 = x2 = x3 = x4 = "";
+		x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
+		if (x1 != NULL) {
+			if (x1[0] != '(')
+				l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
+			else
+				l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
+		}
+	}
+
+#if 0
+	if (SPECIAL_ASCQ(asc,ascq))
+		l += sprintf(foo+l, " (%02Xh)", ascq);
+#endif
+
+	PrintF(("%s\n", foo));
+
+	return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptscsih.h linux/drivers/message/fusion/mptscsih.h
--- v2.4.6/linux/drivers/message/fusion/mptscsih.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/mptscsih.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,247 @@
+/*
+ *  linux/drivers/message/fusion/mptscsih.h
+ *      High performance SCSI / Fibre Channel SCSI Host device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef SCSIHOST_H_INCLUDED
+#define SCSIHOST_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux/version.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	SCSI Public stuff...
+ */
+
+#ifdef __sparc__
+#define MPT_SCSI_CAN_QUEUE	63
+#define MPT_SCSI_CMD_PER_LUN	63
+	/* FIXME!  Still investigating qd=64 hang on sparc64... */
+#else
+#define MPT_SCSI_CAN_QUEUE	64
+#define MPT_SCSI_CMD_PER_LUN	64
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	Various bits and pieces broke within the lk-2.4.0-testN series:-(
+ *	So here are various HACKS to work around them.
+ */
+
+/*
+ *	Conditionalizing with "#ifdef MODULE/#endif" around:
+ *		static Scsi_Host_Template driver_template = XX;
+ *		#include <../../scsi/scsi_module.c>
+ *	lines was REMOVED @ lk-2.4.0-test9
+ *	Issue discovered 20001213 by: sshirron
+ */
+#define MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS			1
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0)
+#	if LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0)
+		/*
+		 *	Super HACK!  -by sralston:-(
+		 *	(good grief; heaven help me!)
+		 */
+#		include <linux/capability.h>
+#		if !defined(CAP_LEASE) && !defined(MODULE)
+#			undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+#		endif
+#	else
+#		ifndef MODULE
+#			undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+#		endif
+#	endif
+#endif
+
+/*
+ *	tq_scheduler disappeared @ lk-2.4.0-test12
+ *	(right when <linux/sched.h> newly defined TQ_ACTIVE)
+ */
+#define HAVE_TQ_SCHED	1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#	include <linux/sched.h>
+#	ifdef TQ_ACTIVE
+#		undef HAVE_TQ_SCHED
+#	endif
+#endif
+#ifdef HAVE_TQ_SCHED
+#define SCHEDULE_TASK(x)		\
+	/*MOD_INC_USE_COUNT*/;		\
+	(x)->next = NULL;		\
+	queue_task(x, &tq_scheduler)
+#else
+#define SCHEDULE_TASK(x)		\
+	/*MOD_INC_USE_COUNT*/;		\
+	if (schedule_task(x) == 0) {	\
+		/*MOD_DEC_USE_COUNT*/;	\
+	}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define x_scsi_detect		mptscsih_detect
+#define x_scsi_release		mptscsih_release
+#define x_scsi_info		mptscsih_info
+#define x_scsi_queuecommand	mptscsih_qcmd
+#define x_scsi_abort		mptscsih_abort
+#define x_scsi_bus_reset	mptscsih_bus_reset
+#define x_scsi_dev_reset	mptscsih_dev_reset
+#define x_scsi_host_reset	mptscsih_host_reset
+#define x_scsi_bios_param	mptscsih_bios_param
+
+#define x_scsi_taskmgmt_bh	mptscsih_taskmgmt_bh
+#define x_scsi_old_abort	mptscsih_old_abort
+#define x_scsi_old_reset	mptscsih_old_reset
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	MPT SCSI Host / Initiator decls...
+ */
+extern	int		 x_scsi_detect(Scsi_Host_Template *);
+extern	int		 x_scsi_release(struct Scsi_Host *host);
+extern	const char	*x_scsi_info(struct Scsi_Host *);
+/*extern	int		 x_scsi_command(Scsi_Cmnd *);*/
+extern	int		 x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+#ifdef MPT_SCSI_USE_NEW_EH
+extern	int		 x_scsi_abort(Scsi_Cmnd *);
+extern	int		 x_scsi_bus_reset(Scsi_Cmnd *);
+extern	int		 x_scsi_dev_reset(Scsi_Cmnd *);
+/*extern	int		 x_scsi_host_reset(Scsi_Cmnd *);*/
+#else
+extern	int		 x_scsi_old_abort(Scsi_Cmnd *);
+extern	int		 x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
+#endif
+extern	int		 x_scsi_bios_param(Disk *, kdev_t, int *);
+extern	void		 x_scsi_taskmgmt_bh(void *);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define PROC_SCSI_DECL
+#else
+#define PROC_SCSI_DECL  proc_name: "mptscsih",
+#endif
+
+#ifdef MPT_SCSI_USE_NEW_EH
+
+#define MPT_SCSIHOST {						\
+	next:				NULL,			\
+	PROC_SCSI_DECL						\
+	name:				"MPT SCSI Host",	\
+	detect:				x_scsi_detect,		\
+	release:			x_scsi_release,		\
+	info:				x_scsi_info,		\
+	command:			NULL,			\
+	queuecommand:			x_scsi_queuecommand,	\
+	eh_strategy_handler:		NULL,			\
+	eh_abort_handler:		x_scsi_abort,		\
+	eh_device_reset_handler:	x_scsi_dev_reset,	\
+	eh_bus_reset_handler:		x_scsi_bus_reset,	\
+	eh_host_reset_handler:		NULL,			\
+	bios_param:			x_scsi_bios_param,	\
+	can_queue:			MPT_SCSI_CAN_QUEUE,	\
+	this_id:			-1,			\
+	sg_tablesize:			25,			\
+	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
+	unchecked_isa_dma:		0,			\
+	use_clustering:			ENABLE_CLUSTERING,	\
+	use_new_eh_code:		1			\
+}
+
+#else
+
+#define MPT_SCSIHOST {						\
+	next:				NULL,			\
+	PROC_SCSI_DECL						\
+	name:				"MPT SCSI Host",	\
+	detect:				x_scsi_detect,		\
+	release:			x_scsi_release,		\
+	info:				x_scsi_info,		\
+	command:			NULL,			\
+	queuecommand:			x_scsi_queuecommand,	\
+	abort:				x_scsi_old_abort,	\
+	reset:				x_scsi_old_reset,	\
+	bios_param:			x_scsi_bios_param,	\
+	can_queue:			MPT_SCSI_CAN_QUEUE,	\
+	this_id:			-1,			\
+	sg_tablesize:			25,			\
+	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
+	unchecked_isa_dma:		0,			\
+	use_clustering:			ENABLE_CLUSTERING	\
+}
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*  include/scsi/scsi.h may not be quite complete...  */
+#ifndef RESERVE_10
+#define RESERVE_10		0x56
+#endif
+#ifndef RELEASE_10
+#define RELEASE_10		0x57
+#endif
+#ifndef PERSISTENT_RESERVE_IN
+#define PERSISTENT_RESERVE_IN	0x5e
+#endif
+#ifndef PERSISTENT_RESERVE_OUT
+#define PERSISTENT_RESERVE_OUT	0x5f
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#endif
+
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/scsi3.h linux/drivers/message/fusion/scsi3.h
--- v2.4.6/linux/drivers/message/fusion/scsi3.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/scsi3.h	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,700 @@
+/*
+ *  linux/drivers/message/fusion/scsi3.h
+ *      SCSI-3 definitions and macros.
+ *      (Ultimately) SCSI-3 definitions; for now, inheriting
+ *      SCSI-2 definitions.
+ *
+ *  Copyright (c) 1996-2001 Steven J. Ralston
+ *  Written By: Steven J. Ralston (19960517)
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: scsi3.h,v 1.4 2001/01/06 15:54:25 sralston Exp $
+ */
+
+#ifndef SCSI3_H_INCLUDED
+#define SCSI3_H_INCLUDED
+/***************************************************************************/
+
+/****************************************************************************
+ *
+ *  Includes
+ */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+/****************************************************************************
+ *
+ *  Defines
+ */
+
+/*
+ *    SCSI Commands
+ */
+#define CMD_TestUnitReady      0x00
+#define CMD_RezeroUnit         0x01  /* direct-access devices */
+#define CMD_Rewind             0x01  /* sequential-access devices */
+#define CMD_RequestSense       0x03
+#define CMD_FormatUnit         0x04
+#define CMD_ReassignBlock      0x07
+#define CMD_Read6              0x08
+#define CMD_Write6             0x0A
+#define CMD_WriteFilemark      0x10
+#define CMD_Space              0x11
+#define CMD_Inquiry            0x12
+#define CMD_ModeSelect6        0x15
+#define CMD_ModeSense6         0x1A
+#define CMD_Reserve6           0x16
+#define CMD_Release6           0x17
+#define CMD_Erase              0x19
+#define CMD_StartStopUnit      0x1b  /* direct-access devices */
+#define CMD_LoadUnload         0x1b  /* sequential-access devices */
+#define CMD_ReceiveDiagnostic  0x1C
+#define CMD_SendDiagnostic     0x1D
+#define CMD_ReadCapacity       0x25
+#define CMD_Read10             0x28
+#define CMD_Write10            0x2A
+#define CMD_WriteVerify        0x2E
+#define CMD_Verify             0x2F
+#define CMD_ReadDefectData     0x37
+#define CMD_LogSelect          0x4C
+#define CMD_LogSense           0x4D
+#define CMD_ModeSelect10       0x55
+#define CMD_Reserve10          0x56
+#define CMD_Release10          0x57
+#define CMD_ModeSense10        0x5A
+#define CMD_ReportLuns         0xA0
+
+/*
+ *    Control byte field
+ */
+#define CONTROL_BYTE_NACA_BIT  0x04
+#define CONTROL_BYTE_Flag_BIT  0x02
+#define CONTROL_BYTE_Link_BIT  0x01
+
+/*
+ *    SCSI Messages
+ */
+#define MSG_COMPLETE             0x00
+#define MSG_EXTENDED             0x01
+#define MSG_SAVE_POINTERS        0x02
+#define MSG_RESTORE_POINTERS     0x03
+#define MSG_DISCONNECT           0x04
+#define MSG_IDERROR              0x05
+#define MSG_ABORT                0x06
+#define MSG_REJECT               0x07
+#define MSG_NOP                  0x08
+#define MSG_PARITY_ERROR         0x09
+#define MSG_LINKED_CMD_COMPLETE  0x0a
+#define MSG_LCMD_COMPLETE_W_FLG  0x0b
+#define MSG_BUS_DEVICE_RESET     0x0c
+#define MSG_ABORT_TAG            0x0d
+#define MSG_CLEAR_QUEUE          0x0e
+#define MSG_INITIATE_RECOVERY    0x0f
+
+#define MSG_RELEASE_RECOVRY      0x10
+#define MSG_TERMINATE_IO         0x11
+
+#define MSG_SIMPLE_QUEUE         0x20
+#define MSG_HEAD_OF_QUEUE        0x21
+#define MSG_ORDERED_QUEUE        0x22
+#define MSG_IGNORE_WIDE_RESIDUE  0x23
+
+#define MSG_IDENTIFY             0x80
+#define MSG_IDENTIFY_W_DISC      0xc0
+
+/*
+ *    SCSI Phases
+ */
+#define PHS_DATA_OUT  0x00
+#define PHS_DATA_IN   0x01
+#define PHS_COMMAND   0x02
+#define PHS_STATUS    0x03
+#define PHS_MSG_OUT   0x06
+#define PHS_MSG_IN    0x07
+
+/*
+ *    Statuses
+ */
+#define STS_GOOD                        0x00
+#define STS_CHECK_CONDITION             0x02
+#define STS_CONDITION_MET               0x04
+#define STS_BUSY                        0x08
+#define STS_INTERMEDIATE                0x10
+#define STS_INTERMEDIATE_CONDITION_MET  0x14
+#define STS_RESERVATION_CONFLICT        0x18
+#define STS_COMMAND_TERMINATED          0x22
+#define STS_TASK_SET_FULL               0x28
+#define    STS_QUEUE_FULL               0x28
+#define STS_ACA_ACTIVE                  0x30
+
+#define STS_VALID_MASK                  0x3e
+
+#define SCSI_STATUS(x)  ((x) & STS_VALID_MASK)
+
+/*
+ *    SCSI QTag Types
+ */
+#define QTAG_SIMPLE     0x20
+#define QTAG_HEAD_OF_Q  0x21
+#define QTAG_ORDERED    0x22
+
+/*
+ *    SCSI Sense Key Definitons
+ */
+#define SK_NO_SENSE         0x00
+#define SK_RECOVERED_ERROR  0x01
+#define SK_NOT_READY        0x02
+#define SK_MEDIUM_ERROR     0x03
+#define SK_HARDWARE_ERROR   0x04
+#define SK_ILLEGAL_REQUEST  0x05
+#define SK_UNIT_ATTENTION   0x06
+#define SK_DATA_PROTECT     0x07
+#define SK_BLANK_CHECK      0x08
+#define SK_VENDOR_SPECIFIC  0x09
+#define SK_COPY_ABORTED     0x0a
+#define SK_ABORTED_COMMAND  0x0b
+#define SK_EQUAL            0x0c
+#define SK_VOLUME_OVERFLOW  0x0d
+#define SK_MISCOMPARE       0x0e
+#define SK_RESERVED         0x0f
+
+
+
+#define SCSI_MAX_INQUIRY_BYTES  96
+#define SCSI_STD_INQUIRY_BYTES  36
+
+#undef USE_SCSI_COMPLETE_INQDATA
+/*
+ *      Structure definition for SCSI Inquiry Data
+ *
+ *  NOTE: The following structure is 96 bytes in size
+ *      iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 36 bytes in size.
+ *  THE CHOICE IS YOURS!
+ */
+typedef struct SCSI_Inquiry_Data
+{
+#ifdef USE_SCSI_COMPLETE_INQDATA
+    u8   InqByte[SCSI_MAX_INQUIRY_BYTES];
+#else
+    u8   InqByte[SCSI_STD_INQUIRY_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+        u32    Periph_Device_Type    : 5,
+               Periph_Qualifier      : 3,
+               Device_Type_Modifier  : 7,
+               Removable_Media       : 1,
+               ANSI_Version          : 3,
+               ECMA_Version          : 3,
+               ISO_Version           : 2,
+               Response_Data_Format  : 4,
+               reserved_0            : 3,
+               AERC                  : 1  ;
+        u32    Additional_Length     : 8,
+               reserved_1            :16,
+               SftReset              : 1,
+               CmdQue                : 1,
+               reserved_2            : 1,
+               Linked                : 1,
+               Sync                  : 1,
+               WBus16                : 1,
+               WBus32                : 1,
+               RelAdr                : 1  ;
+        u8     Vendor_ID[8];
+        u8     Product_ID[16];
+        u8     Revision_Level [4];
+#ifdef USE_SCSI_COMPLETE_INQDATA
+        u8     Vendor_Specific[20];
+        u8     reserved_3[40];
+#endif
+ *
+ */
+
+} SCSI_Inquiry_Data_t;
+
+#define INQ_PERIPHINFO_BYTE            0
+#define   INQ_Periph_Qualifier_MASK      0xe0
+#define   INQ_Periph_Device_Type_MASK    0x1f
+
+#define INQ_Peripheral_Qualifier(inqp) \
+    (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5)
+#define INQ_Peripheral_Device_Type(inqp) \
+    (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK)
+
+
+#define INQ_DEVTYPEMOD_BYTE            1
+#define   INQ_RMB_BIT                    0x80
+#define   INQ_Device_Type_Modifier_MASK  0x7f
+
+#define INQ_Removable_Medium(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT)
+#define INQ_Device_Type_Modifier(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK)
+
+
+#define INQ_VERSIONINFO_BYTE           2
+#define   INQ_ISO_Version_MASK           0xc0
+#define   INQ_ECMA_Version_MASK          0x38
+#define   INQ_ANSI_Version_MASK          0x07
+
+#define INQ_ISO_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK)
+#define INQ_ECMA_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK)
+#define INQ_ANSI_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK)
+
+
+#define INQ_BYTE3                      3
+#define   INQ_AERC_BIT                   0x80
+#define   INQ_TrmTsk_BIT                 0x40
+#define   INQ_NormACA_BIT                0x20
+#define   INQ_RDF_MASK                   0x0F
+
+#define INQ_AER_Capable(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT)
+#define INQ_TrmTsk(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT)
+#define INQ_NormACA(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT)
+#define INQ_Response_Data_Format(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK)
+
+
+#define INQ_CAPABILITY_BYTE            7
+#define   INQ_RelAdr_BIT                 0x80
+#define   INQ_WBus32_BIT                 0x40
+#define   INQ_WBus16_BIT                 0x20
+#define   INQ_Sync_BIT                   0x10
+#define   INQ_Linked_BIT                 0x08
+  /*      INQ_Reserved BIT               0x40 */
+#define   INQ_CmdQue_BIT                 0x02
+#define   INQ_SftRe_BIT                  0x01
+
+#define IS_RelAdr_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT)
+#define IS_WBus32_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT)
+#define IS_WBus16_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT)
+#define IS_Sync_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT)
+#define IS_Linked_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT)
+#define IS_CmdQue_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT)
+#define IS_SftRe_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT)
+
+#define INQ_Width_BITS \
+    (INQ_WBus32_BIT | INQ_WBus16_BIT)
+#define IS_Wide_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS)
+
+
+/*
+ *      SCSI peripheral device types
+ */
+#define SCSI_TYPE_DAD               0x00  /* Direct Access Device */
+#define SCSI_TYPE_SAD               0x01  /* Sequential Access Device */
+#define SCSI_TYPE_TAPE  SCSI_TYPE_SAD
+#define SCSI_TYPE_PRT               0x02  /* Printer */
+#define SCSI_TYPE_PROC              0x03  /* Processor */
+#define SCSI_TYPE_WORM              0x04
+#define SCSI_TYPE_CDROM             0x05
+#define SCSI_TYPE_SCAN              0x06  /* Scanner */
+#define SCSI_TYPE_OPTICAL           0x07  /* Magneto/Optical */
+#define SCSI_TYPE_CHANGER           0x08
+#define SCSI_TYPE_COMM              0x09  /* Communications device */
+#define SCSI_TYPE_UNKNOWN           0x1f
+#define SCSI_TYPE_UNCONFIGURED_LUN  0x7f
+
+#define SCSI_TYPE_MAX_KNOWN         SCSI_TYPE_COMM
+
+/*
+ *      Peripheral Qualifiers
+ */
+#define DEVICE_PRESENT     0x00
+#define LUN_NOT_PRESENT    0x01
+#define LUN_NOT_SUPPORTED  0x03
+
+/*
+ *      ANSI Versions
+ */
+#ifndef SCSI_1
+#define SCSI_1  0x01
+#endif
+#ifndef SCSI_2
+#define SCSI_2  0x02
+#endif
+#ifndef SCSI_3
+#define SCSI_3  0x03
+#endif
+
+
+#define SCSI_MAX_SENSE_BYTES  255
+#define SCSI_STD_SENSE_BYTES   18
+#define SCSI_PAD_SENSE_BYTES      (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES)
+
+#undef USE_SCSI_COMPLETE_SENSE
+/*
+ *      Structure definition for SCSI Sense Data
+ *
+ *  NOTE: The following structure is 255 bytes in size
+ *      iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 19 bytes in size.
+ *  THE CHOICE IS YOURS!
+ *
+ */
+typedef struct SCSI_Sense_Data
+{
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8       SenseByte[SCSI_MAX_SENSE_BYTES];
+#else
+    u8       SenseByte[SCSI_STD_SENSE_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+    u8     Error_Code                :4,            // 0x00
+           Error_Class               :3,
+           Valid                     :1
+     ;
+    u8     Segment_Number                           // 0x01
+     ;
+    u8     Sense_Key                 :4,            // 0x02
+           Reserved                  :1,
+           Incorrect_Length_Indicator:1,
+           End_Of_Media              :1,
+           Filemark                  :1
+     ;
+    u8     Information_MSB;                         // 0x03
+    u8     Information_Byte2;                       // 0x04
+    u8     Information_Byte1;                       // 0x05
+    u8     Information_LSB;                         // 0x06
+    u8     Additional_Length;                       // 0x07
+
+    u32    Command_Specific_Information;            // 0x08 - 0x0b
+
+    u8     Additional_Sense_Code;                   // 0x0c
+    u8     Additional_Sense_Code_Qualifier;         // 0x0d
+    u8     Field_Replaceable_Unit_Code;             // 0x0e
+    u8     Illegal_Req_Bit_Pointer   :3,            // 0x0f
+           Illegal_Req_Bit_Valid     :1,
+           Illegal_Req_Reserved      :2,
+           Illegal_Req_Cmd_Data      :1,
+           Sense_Key_Specific_Valid  :1
+     ;
+    u16    Sense_Key_Specific_Data;                 // 0x10 - 0x11
+
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8     Additional_Sense_Data[SCSI_PAD_SENSE_BYTES];
+#else
+    u8     Additional_Sense_Data[1];
+#endif
+ *
+ */
+
+} SCSI_Sense_Data_t;
+
+
+#define SD_ERRCODE_BYTE                0
+#define   SD_Valid_BIT                   0x80
+#define   SD_Error_Code_MASK             0x7f
+#define SD_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT)
+#define SD_Error_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK)
+
+
+#define SD_SEGNUM_BYTE                 1
+#define SD_Segment_Number(sdp)  (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE))
+
+
+#define SD_SENSEKEY_BYTE               2
+#define   SD_Filemark_BIT                0x80
+#define   SD_EOM_BIT                     0x40
+#define   SD_ILI_BIT                     0x20
+#define   SD_Sense_Key_MASK              0x0f
+#define SD_Filemark(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT)
+#define SD_EOM(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT)
+#define SD_ILI(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT)
+#define SD_Sense_Key(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK)
+
+
+#define SD_INFO3_BYTE                  3
+#define SD_INFO2_BYTE                  4
+#define SD_INFO1_BYTE                  5
+#define SD_INFO0_BYTE                  6
+#define SD_Information3(sdp)  (int)(*((u8*)(sdp)+SD_INFO3_BYTE))
+#define SD_Information2(sdp)  (int)(*((u8*)(sdp)+SD_INFO2_BYTE))
+#define SD_Information1(sdp)  (int)(*((u8*)(sdp)+SD_INFO1_BYTE))
+#define SD_Information0(sdp)  (int)(*((u8*)(sdp)+SD_INFO0_BYTE))
+
+
+#define SD_ADDL_LEN_BYTE               7
+#define SD_Additional_Sense_Length(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE))
+#define SD_Addl_Sense_Len  SD_Additional_Sense_Length
+
+
+#define SD_CMD_SPECIFIC3_BYTE          8
+#define SD_CMD_SPECIFIC2_BYTE          9
+#define SD_CMD_SPECIFIC1_BYTE         10
+#define SD_CMD_SPECIFIC0_BYTE         11
+#define SD_Cmd_Specific_Info3(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE))
+#define SD_Cmd_Specific_Info2(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE))
+#define SD_Cmd_Specific_Info1(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE))
+#define SD_Cmd_Specific_Info0(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE))
+
+
+#define SD_ADDL_SENSE_CODE_BYTE       12
+#define SD_Additional_Sense_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE))
+#define SD_Addl_Sense_Code  SD_Additional_Sense_Code
+#define SD_ASC  SD_Additional_Sense_Code
+
+
+#define SD_ADDL_SENSE_CODE_QUAL_BYTE  13
+#define SD_Additional_Sense_Code_Qualifier(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE))
+#define SD_Addl_Sense_Code_Qual  SD_Additional_Sense_Code_Qualifier
+#define SD_ASCQ  SD_Additional_Sense_Code_Qualifier
+
+
+#define SD_FIELD_REPL_UNIT_CODE_BYTE  14
+#define SD_Field_Replaceable_Unit_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE))
+#define SD_Field_Repl_Unit_Code  SD_Field_Replaceable_Unit_Code
+#define SD_FRUC  SD_Field_Replaceable_Unit_Code
+#define SD_FRU  SD_Field_Replaceable_Unit_Code
+
+
+/*
+ *  Sense-Key Specific offsets and macros.
+ */
+#define SD_SKS2_BYTE                  15
+#define   SD_SKS_Valid_BIT               0x80
+#define   SD_SKS_Cmd_Data_BIT            0x40
+#define   SD_SKS_Bit_Ptr_Valid_BIT       0x08
+#define   SD_SKS_Bit_Ptr_MASK            0x07
+#define SD_SKS1_BYTE                  16
+#define SD_SKS0_BYTE                  17
+#define SD_Sense_Key_Specific_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT)
+#define SD_SKS_Valid  SD_Sense_Key_Specific_Valid
+#define SD_SKS_CDB_Error(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT)
+#define SD_Was_Illegal_Request  SD_SKS_CDB_Error
+#define SD_SKS_Bit_Pointer_Valid(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT)
+#define SD_SKS_Bit_Pointer(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK)
+#define SD_Field_Pointer(sdp)  \
+    (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \
+      + *((u8*)(sdp)+SD_SKS0_BYTE) )
+#define SD_Bad_Byte  SD_Field_Pointer
+#define SD_Actual_Retry_Count  SD_Field_Pointer
+#define SD_Progress_Indication  SD_Field_Pointer
+
+/*
+ *  Mode Sense Write Protect Mask
+ */
+#define WRITE_PROTECT_MASK      0X80
+
+/*
+ *  Medium Type Codes
+ */
+#define OPTICAL_DEFAULT                 0x00
+#define OPTICAL_READ_ONLY_MEDIUM        0x01
+#define OPTICAL_WRITE_ONCE_MEDIUM       0x02
+#define OPTICAL_READ_WRITABLE_MEDIUM    0x03
+#define OPTICAL_RO_OR_WO_MEDIUM         0x04
+#define OPTICAL_RO_OR_RW_MEDIUM         0x05
+#define OPTICAL_WO_OR_RW_MEDIUM         0x06
+
+
+
+/*
+ *    Structure definition for READ6, WRITE6 (6-byte CDB)
+ */
+typedef struct SCSI_RW6_CDB
+{
+    u32    OpCode      :8,
+           LBA_HI      :5,    /* 5 MSBit's of the LBA */
+           Lun         :3,
+           LBA_MID     :8,    /* NOTE: total of 21 bits in LBA */
+           LBA_LO      :8  ;  /* Max LBA = 0x001fffff          */
+    u8     BlockCount;
+    u8     Control;
+} SCSI_RW6_t;
+
+#define MAX_RW6_LBA  ((u32)0x001fffff)
+
+/*
+ *  Structure definition for READ10, WRITE10 (10-byte CDB)
+ *
+ *    NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for
+ *    the ADP-92 DAC only.  In the SCSI2 spec. this same bit is defined as a
+ *    FUA (forced unit access) bit for READs and WRITEs.  Since this driver
+ *    does not use the FUA, this bit is defined as it is used by the ADP-92.
+ *    Also, for READ CAPACITY, only the OpCode field is used.
+ */
+typedef struct SCSI_RW10_CDB
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u32    LBA;
+    u8     Reserved2;
+    u16    BlockCount;
+    u8     Control;
+} SCSI_RW10_t;
+
+#define PARITY_CHECK  0x08    /* parity check bit - byte[1], bit 3 */
+
+    /*
+     *  Structure definition for data returned by READ CAPACITY cmd;
+     *  READ CAPACITY data
+     */
+    typedef struct READ_CAP_DATA
+    {
+        u32    MaxLBA;
+        u32    BlockBytes;
+    } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t;
+
+
+/*
+ *  Structure definition for FORMAT UNIT CDB (6-byte CDB)
+ */
+typedef struct _SCSI_FORMAT_UNIT
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     VendorSpecific;
+    u16    Interleave;
+    u8     Control;
+} SCSI_FORMAT_UNIT_t;
+
+/*
+ *    Structure definition for REQUEST SENSE (6-byte CDB)
+ */
+typedef struct _SCSI_REQUEST_SENSE
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     Reserved2;
+    u8     Reserved3;
+    u8     AllocLength;
+    u8     Control;
+} SCSI_REQ_SENSE_t;
+
+/*
+ *  Structure definition for REPORT LUNS (12-byte CDB)
+ */
+typedef struct _SCSI_REPORT_LUNS
+{
+    u8     OpCode;
+    u8     Reserved1[5];
+    u32    AllocationLength;
+    u8     Reserved2;
+    u8     Control;
+} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t;
+
+    /*
+     *  (per-level) LUN information bytes
+     */
+/*
+ *  Following doesn't work on ARMCC compiler
+ *  [apparently] because it pads every struct
+ *  to be multiple of 4 bytes!
+ *  So SCSI_LUN_LEVELS_t winds up being 16
+ *  bytes instead of 8!
+ *
+    typedef struct LUN_INFO
+    {
+        u8     AddrMethod_plus_LunOrBusNumber;
+        u8     LunOrTarget;
+    } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t;
+
+    typedef struct LUN_LEVELS
+    {
+        SCSI_LUN_INFO_t  LUN_0;
+        SCSI_LUN_INFO_t  LUN_1;
+        SCSI_LUN_INFO_t  LUN_2;
+        SCSI_LUN_INFO_t  LUN_3;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+*/
+    /*
+     *  All 4 levels (8 bytes) of LUN information
+     */
+    typedef struct LUN_LEVELS
+    {
+        u8     LVL1_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL1_LunOrTarget;
+        u8     LVL2_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL2_LunOrTarget;
+        u8     LVL3_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL3_LunOrTarget;
+        u8     LVL4_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL4_LunOrTarget;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+
+    /*
+     *  Structure definition for data returned by REPORT LUNS cmd;
+     *  LUN reporting parameter list format
+     */
+    typedef struct LUN_REPORT
+    {
+        u32                LunListLength;
+        u32                Reserved;
+        SCSI_LUN_LEVELS_t  LunInfo[1];
+    } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t;
+
+/****************************************************************************
+ *
+ *  Externals
+ */
+
+/****************************************************************************
+ *
+ *  Public Typedefs & Related Defines
+ */
+
+/****************************************************************************
+ *
+ *  Macros (embedded, above)
+ */
+
+/****************************************************************************
+ *
+ *  Public Variables
+ */
+
+/****************************************************************************
+ *
+ *  Public Prototypes (module entry points)
+ */
+
+
+/***************************************************************************/
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/scsiops.c linux/drivers/message/fusion/scsiops.c
--- v2.4.6/linux/drivers/message/fusion/scsiops.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/message/fusion/scsiops.c	Fri Jul  6 17:03:11 2001
@@ -0,0 +1,309 @@
+
+static const char *ScsiOpcodeString[256] = {
+	"TEST UNIT READY\0\01",				/* 00h */
+	"REWIND\0\002"
+		"\001REZERO UNIT",			/* 01h */
+	"\0\0",						/* 02h */
+	"REQUEST SENSE\0\01",				/* 03h */
+	"FORMAT UNIT\0\03"
+		"\001FORMAT MEDIUM\0"
+		"\002FORMAT",				/* 04h */
+	"READ BLOCK LIMITS\0\1",			/* 05h */
+	"\0\0",						/* 06h */
+	"REASSIGN BLOCKS\0\02"
+		"\010INITIALIZE ELEMENT STATUS",	/* 07h */
+	"READ(06)\0\04"
+		"\001READ\0"
+		"\003RECEIVE\0"
+		"\011GET MESSAGE(06)",			/* 08h */
+	"\0\0",						/* 09h */
+	"WRITE(06)\0\05"
+		"\001WRITE\0"
+		"\002PRINT\0"
+		"\003SEND(6)\0"
+		"\011SEND MESSAGE(06)",			/* 0Ah */
+	"SEEK(06)\0\02"
+		"\003SLEW AND PRINT",			/* 0Bh */
+	"\0\0",						/* 0Ch */
+	"\0\0",						/* 0Dh */
+	"\0\0",						/* 0Eh */
+	"READ REVERSE\0\01",				/* 0Fh */
+	"WRITE FILEMARKS\0\02"
+		"\003SYNCRONIZE BUFFER",		/* 10h */
+	"SPACE(6)\0\01",				/* 11h */
+	"INQUIRY\0\01",					/* 12h */
+	"VERIFY\0\01",					/* 13h */
+	"RECOVER BUFFERED DATA\0\01",			/* 14h */
+	"MODE SELECT(06)\0\01",				/* 15h */
+	"RESERVE(06)\0\02"
+		"\010RESERVE ELEMENT(06)",		/* 16h */
+	"RELEASE(06)\0\02"
+		"\010RELEASE ELEMENT(06)",		/* 17h */
+	"COPY\0\01",					/* 18h */
+	"ERASE\0\01",					/* 19h */
+	"MODE SENSE(06)\0\01",				/* 1Ah */
+	"STOP START UNIT\0\04"
+		"\001LOAD UNLOAD\0"
+		"\002STOP PRINT\0"
+		"\006SCAN\0\002",			/* 1Bh */
+	"RECEIVE DIAGNOSTIC RESULTS\0\01",		/* 1Ch */
+	"SEND DIAGNOSTIC\0\01",				/* 1Dh */
+	"PREVENT ALLOW MEDIUM REMOVAL\0\01",		/* 1Eh */
+	"\0\0",						/* 1Fh */
+	"\0\0",						/* 20h */
+	"\0\0",						/* 21h */
+	"\0\0",						/* 22h */
+	"READ FORMAT CAPACITIES\0\01",			/* 23h */
+	"SET WINDOW\0\01",				/* 24h */
+	"READ CAPACITY\0\03"
+		"\006GET WINDOW\0"
+		"\037FREAD CARD CAPACITY",		/* 25h */
+	"\0\0",						/* 26h */
+	"\0\0",						/* 27h */
+	"READ(10)\0\02"
+		"\011GET MESSAGE(10)",			/* 28h */
+	"READ GENERATION\0\01",				/* 29h */
+	"WRITE(10)\0\03"
+		"\011SEND(10)\0"
+		"\011SEND MESSAGE(10)",			/* 2Ah */
+	"SEEK(10)\0\03"
+		"LOCATE(10)\0"
+		"POSITION TO ELEMENT",			/* 2Bh */
+	"ERASE(10)\0\01",				/* 2Ch */
+	"READ UPDATED BLOCK\0\01",			/* 2Dh */
+	"WRITE AND VERIFY(10)\0\01",			/* 2Eh */
+	"VERIFY(10)\0\01",				/* 2Fh */
+	"SEARCH DATA HIGH(10)\0\01",			/* 30h */
+	"SEARCH DATA EQUAL(10)\0\02"
+		"OBJECT POSITION",			/* 31h */
+	"SEARCH DATA LOW(10)\0\01",			/* 32h */
+	"SET LIMITS(10)\0\01",				/* 33h */
+	"PRE-FETCH(10)\0\03"
+		"READ POSITION\0"
+		"GET DATA BUFFER STATUS",		/* 34h */
+	"SYNCHRONIZE CACHE(10)\0\01",			/* 35h */
+	"LOCK UNLOCK CACHE(10)\0\01",			/* 36h */
+	"READ DEFECT DATA(10)\0\01",			/* 37h */
+	"MEDIUM SCAN\0\01",				/* 38h */
+	"COMPARE\0\01",					/* 39h */
+	"COPY AND VERIFY\0\01",				/* 3Ah */
+	"WRITE BUFFER\0\01",				/* 3Bh */
+	"READ BUFFER\0\01",				/* 3Ch */
+	"UPDATE BLOCK\0\01",				/* 3Dh */
+	"READ LONG\0\01",				/* 3Eh */
+	"WRITE LONG\0\01",				/* 3Fh */
+	"CHANGE DEFINITION\0\01",			/* 40h */
+	"WRITE SAME(10)\0\01",				/* 41h */
+	"READ SUB-CHANNEL\0\01",			/* 42h */
+	"READ TOC/PMA/ATIP\0\01",			/* 43h */
+	"REPORT DENSITY SUPPORT\0\01",			/* 44h */
+	"READ HEADER\0\01",				/* 44h */
+	"PLAY AUDIO(10)\0\01",				/* 45h */
+	"GET CONFIGURATION\0\01",			/* 46h */
+	"PLAY AUDIO MSF\0\01",				/* 47h */
+	"PLAY AUDIO TRACK INDEX\0\01",			/* 48h */
+	"PLAY TRACK RELATIVE(10)\0\01",			/* 49h */
+	"GET EVENT STATUS NOTIFICATION\0\01",		/* 4Ah */
+	"PAUSE/RESUME\0\01",				/* 4Bh */
+	"LOG SELECT\0\01",				/* 4Ch */
+	"LOG SENSE\0\01",				/* 4Dh */
+	"STOP PLAY/SCAN\0\01",				/* 4Eh */
+	"\0\0",						/* 4Fh */
+	"XDWRITE(10)\0\01",				/* 50h */
+	"XPWRITE(10)\0\02"
+		"READ DISC INFORMATION",		/* 51h */
+	"XDREAD(10)\0\01"
+		"READ TRACK INFORMATION",		/* 52h */
+	"RESERVE TRACK\0\01",				/* 53h */
+	"SEND OPC INFORMATION\0\01",			/* 54h */
+	"MODE SELECT(10)\0\01",				/* 55h */
+	"RESERVE(10)\0\02"
+		"RESERVE ELEMENT(10)",			/* 56h */
+	"RELEASE(10)\0\02"
+		"RELEASE ELEMENT(10)",			/* 57h */
+	"REPAIR TRACK\0\01",				/* 58h */
+	"READ MASTER CUE\0\01",				/* 59h */
+	"MODE SENSE(10)\0\01",				/* 5Ah */
+	"CLOSE TRACK/SESSION\0\01",			/* 5Bh */
+	"READ BUFFER CAPACITY\0\01",			/* 5Ch */
+	"SEND CUE SHEET\0\01",				/* 5Dh */
+	"PERSISTENT RESERVE IN\0\01",			/* 5Eh */
+	"PERSISTENT RESERVE OUT\0\01",			/* 5Fh */
+	"\0\0",						/* 60h */
+	"\0\0",						/* 61h */
+	"\0\0",						/* 62h */
+	"\0\0",						/* 63h */
+	"\0\0",						/* 64h */
+	"\0\0",						/* 65h */
+	"\0\0",						/* 66h */
+	"\0\0",						/* 67h */
+	"\0\0",						/* 68h */
+	"\0\0",						/* 69h */
+	"\0\0",						/* 6Ah */
+	"\0\0",						/* 6Bh */
+	"\0\0",						/* 6Ch */
+	"\0\0",						/* 6Dh */
+	"\0\0",						/* 6Eh */
+	"\0\0",						/* 6Fh */
+	"\0\0",						/* 70h */
+	"\0\0",						/* 71h */
+	"\0\0",						/* 72h */
+	"\0\0",						/* 73h */
+	"\0\0",						/* 74h */
+	"\0\0",						/* 75h */
+	"\0\0",						/* 76h */
+	"\0\0",						/* 77h */
+	"\0\0",						/* 78h */
+	"\0\0",						/* 79h */
+	"\0\0",						/* 7Ah */
+	"\0\0",						/* 7Bh */
+	"\0\0",						/* 7Ch */
+	"\0\0",						/* 7Eh */
+	"\0\0",						/* 7Eh */
+	"\0\0",						/* 7Fh */
+	"XDWRITE EXTENDED(16)\0\01",			/* 80h */
+	"REBUILD(16)\0\01",				/* 81h */
+	"REGENERATE(16)\0\01",				/* 82h */
+	"EXTENDED COPY\0\01",				/* 83h */
+	"RECEIVE COPY RESULTS\0\01",			/* 84h */
+	"ACCESS CONTROL IN  [proposed]\0\01",		/* 86h */
+	"ACCESS CONTROL OUT  [proposed]\0\01",		/* 87h */
+	"READ(16)\0\01",				/* 88h */
+	"DEVICE LOCKS  [proposed]\0\01",		/* 89h */
+	"WRITE(16)\0\01",				/* 8Ah */
+	"\0\0",						/* 8Bh */
+	"READ ATTRIBUTES [proposed]\0\01",		/* 8Ch */
+	"WRITE ATTRIBUTES [proposed]\0\01",		/* 8Dh */
+	"WRITE AND VERIFY(16)\0\01",			/* 8Eh */
+	"VERIFY(16)\0\01",				/* 8Fh */
+	"PRE-FETCH(16)\0\01",				/* 90h */
+	"SYNCHRONIZE CACHE(16)\0\02"
+		"SPACE(16) [1]",			/* 91h */
+	"LOCK UNLOCK CACHE(16)\0\02"
+		"LOCATE(16) [1]",			/* 92h */
+	"WRITE SAME(16)\0\01",				/* 93h */
+	"[usage proposed by SCSI Socket Services project]\0\01",	/* 94h */
+	"[usage proposed by SCSI Socket Services project]\0\01",	/* 95h */
+	"[usage proposed by SCSI Socket Services project]\0\01",	/* 96h */
+	"[usage proposed by SCSI Socket Services project]\0\01",	/* 97h */
+	"MARGIN CONTROL [proposed]\0\01",		/* 98h */
+	"\0\0",						/* 99h */
+	"\0\0",						/* 9Ah */
+	"\0\0",						/* 9Bh */
+	"\0\0",						/* 9Ch */
+	"\0\0",						/* 9Dh */
+	"SERVICE ACTION IN [proposed]\0\01",		/* 9Eh */
+	"SERVICE ACTION OUT [proposed]\0\01",		/* 9Fh */
+	"REPORT LUNS\0\01",				/* A0h */
+	"BLANK\0\01",					/* A1h */
+	"SEND EVENT\0\01",				/* A2h */
+	"MAINTENANCE (IN)\0\02"
+		"SEND KEY",				/* A3h */
+	"MAINTENANCE (OUT)\0\02"
+		"REPORT KEY",				/* A4h */
+	"MOVE MEDIUM\0\02"
+		"PLAY AUDIO(12)",			/* A5h */
+	"EXCHANGE MEDIUM\0\02"
+		"LOAD/UNLOAD C/DVD",			/* A6h */
+	"MOVE MEDIUM ATTACHED\0\02"
+		"SET READ AHEAD\0\01",			/* A7h */
+	"READ(12)\0\02"
+		"GET MESSAGE(12)",			/* A8h */
+	"PLAY TRACK RELATIVE(12)\0\01",			/* A9h */
+	"WRITE(12)\0\02"
+		"SEND MESSAGE(12)",			/* AAh */
+	"\0\0",						/* ABh */
+	"ERASE(12)\0\02"
+		"GET PERFORMANCE",			/* ACh */
+	"READ DVD STRUCTURE\0\01",			/* ADh */
+	"WRITE AND VERIFY(12)\0\01",			/* AEh */
+	"VERIFY(12)\0\01",				/* AFh */
+	"SEARCH DATA HIGH(12)\0\01",			/* B0h */
+	"SEARCH DATA EQUAL(12)\0\01",			/* B1h */
+	"SEARCH DATA LOW(12)\0\01",			/* B2h */
+	"SET LIMITS(12)\0\01",				/* B3h */
+	"READ ELEMENT STATUS ATTACHED\0\01",		/* B4h */
+	"REQUEST VOLUME ELEMENT ADDRESS\0\01",		/* B5h */
+	"SEND VOLUME TAG\0\02"
+		"SET STREAMING",			/* B6h */
+	"READ DEFECT DATA(12)\0\01",			/* B7h */
+	"READ ELEMENT STATUS\0\01",			/* B8h */
+	"READ CD MSF\0\01",				/* B9h */
+	"REDUNDANCY GROUP (IN)\0\02"
+		"SCAN",					/* BAh */
+	"REDUNDANCY GROUP (OUT)\0\02"
+		"SET CD-ROM SPEED",			/* BBh */
+	"SPARE (IN)\0\02"
+		"PLAY CD",				/* BCh */
+	"SPARE (OUT)\0\02"
+		"MECHANISM STATUS",			/* BDh */
+	"VOLUME SET (IN)\0\02"
+		"READ CD",				/* BEh */
+	"VOLUME SET (OUT)\0\0\02"
+		"SEND DVD STRUCTURE",			/* BFh */
+	"\0\0",						/* C0h */
+	"\0\0",						/* C1h */
+	"\0\0",						/* C2h */
+	"\0\0",						/* C3h */
+	"\0\0",						/* C4h */
+	"\0\0",						/* C5h */
+	"\0\0",						/* C6h */
+	"\0\0",						/* C7h */
+	"\0\0",						/* C8h */
+	"\0\0",						/* C9h */
+	"\0\0",						/* CAh */
+	"\0\0",						/* CBh */
+	"\0\0",						/* CCh */
+	"\0\0",						/* CDh */
+	"\0\0",						/* CEh */
+	"\0\0",						/* CFh */
+	"\0\0",						/* D0h */
+	"\0\0",						/* D1h */
+	"\0\0",						/* D2h */
+	"\0\0",						/* D3h */
+	"\0\0",						/* D4h */
+	"\0\0",						/* D5h */
+	"\0\0",						/* D6h */
+	"\0\0",						/* D7h */
+	"\0\0",						/* D8h */
+	"\0\0",						/* D9h */
+	"\0\0",						/* DAh */
+	"\0\0",						/* DBh */
+	"\0\0",						/* DCh */
+	"\0\0",						/* DEh */
+	"\0\0",						/* DEh */
+	"\0\0",						/* DFh */
+	"\0\0",						/* E0h */
+	"\0\0",						/* E1h */
+	"\0\0",						/* E2h */
+	"\0\0",						/* E3h */
+	"\0\0",						/* E4h */
+	"\0\0",						/* E5h */
+	"\0\0",						/* E6h */
+	"\0\0",						/* E7h */
+	"\0\0",						/* E8h */
+	"\0\0",						/* E9h */
+	"\0\0",						/* EAh */
+	"\0\0",						/* EBh */
+	"\0\0",						/* ECh */
+	"\0\0",						/* EDh */
+	"\0\0",						/* EEh */
+	"\0\0",						/* EFh */
+	"\0\0",						/* F0h */
+	"\0\0",						/* F1h */
+	"\0\0",						/* F2h */
+	"\0\0",						/* F3h */
+	"\0\0",						/* F4h */
+	"\0\0",						/* F5h */
+	"\0\0",						/* F6h */
+	"\0\0",						/* F7h */
+	"\0\0",						/* F8h */
+	"\0\0",						/* F9h */
+	"\0\0",						/* FAh */
+	"\0\0",						/* FBh */
+	"\0\0",						/* FEh */
+	"\0\0",						/* FEh */
+	"\0\0",						/* FEh */
+	"\0\0"						/* FFh */
+};
+
diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.4.6/linux/drivers/net/3c509.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/3c509.c	Sun Jul  8 13:14:00 2001
@@ -174,7 +174,7 @@
 };
 #endif /* CONFIG_MCA */
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
 static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -203,8 +203,8 @@
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
 
 static u16 el3_isapnp_phys_addr[8][3];
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 static int nopnp;
-#endif /* CONFIG_ISAPNP */
 
 int __init el3_probe(struct net_device *dev)
 {
@@ -214,9 +214,9 @@
 	u16 phys_addr[3];
 	static int current_tag;
 	int mca_slot = -1;
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
 	static int pnp_cards;
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
 	if (dev) SET_MODULE_OWNER(dev);
 
@@ -320,7 +320,7 @@
 	}
 #endif /* CONFIG_MCA */
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
 	if (nopnp == 1)
 		goto no_pnp;
 
@@ -356,7 +356,7 @@
 		}
 	}
 no_pnp:
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
 	/* Select an open I/O location at 0x1*0 to do contention select. */
 	for ( ; id_port < 0x200; id_port += 0x10) {
@@ -402,7 +402,7 @@
 		phys_addr[i] = htons(id_read_eeprom(i));
 	}
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
 	if (nopnp == 0) {
 		/* The ISA PnP 3c509 cards respond to the ID sequence.
 		   This check is needed in order not to register them twice. */
@@ -422,7 +422,7 @@
 			}
 		}
 	}
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
 	{
 		unsigned int iobase = id_read_eeprom(8);
diff -u --recursive --new-file v2.4.6/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.4.6/linux/drivers/net/8139too.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/8139too.c	Sun Jul  8 13:17:30 2001
@@ -137,7 +137,7 @@
 */
 
 #define DRV_NAME	"8139too"
-#define DRV_VERSION	"0.9.18-pre4"
+#define DRV_VERSION	"0.9.18"
 
 
 #include <linux/config.h>
@@ -209,7 +209,7 @@
 #define RX_BUF_PAD 16
 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
 #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
-#define RX_EARLY_THRESH 2
+#define RX_EARLY_THRESH 14
 
 /* Number of Tx descriptor registers. */
 #define NUM_TX_DESC	4
diff -u --recursive --new-file v2.4.6/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.4.6/linux/drivers/net/Config.in	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/Config.in	Fri Jul  6 16:48:50 2001
@@ -207,6 +207,7 @@
 
 dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI
 dep_mbool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I $CONFIG_ACENIC
+dep_tristate 'D-Link 2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI
 dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
diff -u --recursive --new-file v2.4.6/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.4.6/linux/drivers/net/Makefile	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/Makefile	Fri Jul  6 16:48:50 2001
@@ -207,6 +207,7 @@
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_DL2K) += dl2k.o
 
 ifeq ($(CONFIG_ARCH_ACORN),y)
 mod-subdirs	+= ../acorn/net
diff -u --recursive --new-file v2.4.6/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.4.6/linux/drivers/net/acenic.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/acenic.c	Wed Jul  4 14:41:33 2001
@@ -2731,7 +2731,7 @@
 	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 
-	if ((new_mtu < 68) || (new_mtu > ACE_JUMBO_MTU))
+	if (new_mtu > ACE_JUMBO_MTU)
 		return -EINVAL;
 
 	writel(new_mtu + ETH_HLEN + 4, &regs->IfMtu);
diff -u --recursive --new-file v2.4.6/linux/drivers/net/arlan.c linux/drivers/net/arlan.c
--- v2.4.6/linux/drivers/net/arlan.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/arlan.c	Wed Jul  4 14:41:33 2001
@@ -1144,7 +1144,7 @@
 	struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf;
 
 	ARLAN_DEBUG_ENTRY("arlan_change_mtu");
-	if ((new_mtu < 68) || (new_mtu > 2032))
+	if (new_mtu > 2032)
 		return -EINVAL;
 	dev->mtu = new_mtu;
 	if (new_mtu < 256)
diff -u --recursive --new-file v2.4.6/linux/drivers/net/au1000_eth.c linux/drivers/net/au1000_eth.c
--- v2.4.6/linux/drivers/net/au1000_eth.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/au1000_eth.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,1266 @@
+/*
+ *
+ * Alchemy Semi Au1000 ethernet driver
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * 
+ */
+
+#ifndef __mips__
+#error This driver only works with MIPS architectures!
+#endif
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <asm/au1000.h>
+#include "au1000_eth.h"
+
+#ifdef AU1000_ETH_DEBUG
+static int au1000_debug = 10;
+#else
+static int au1000_debug = 3;
+#endif
+
+// prototypes
+static void *dma_alloc(size_t, dma_addr_t *);
+static void dma_free(void *, size_t);
+static void hard_stop(struct net_device *);
+static int __init au1000_probe1(struct net_device *, long, int, int);
+static int au1000_init(struct net_device *);
+static int au1000_open(struct net_device *);
+static int au1000_close(struct net_device *);
+static int au1000_tx(struct sk_buff *, struct net_device *);
+static int au1000_rx(struct net_device *);
+static void au1000_interrupt(int, void *, struct pt_regs *);
+static void au1000_tx_timeout(struct net_device *);
+static int au1000_set_config(struct net_device *dev, struct ifmap *map);
+static void set_rx_mode(struct net_device *);
+static struct net_device_stats *au1000_get_stats(struct net_device *);
+static inline void update_tx_stats(struct net_device *, u32, u32);
+static inline void update_rx_stats(struct net_device *, u32);
+static void au1000_timer(unsigned long);
+static void cleanup_buffers(struct net_device *);
+static int au1000_ioctl(struct net_device *, struct ifreq *, int);
+static int mdio_read(struct net_device *, int, int);
+static void mdio_write(struct net_device *, int, int, u16);
+static inline void sync(void);
+
+extern  void ack_rise_edge_irq(unsigned int);
+
+static int next_dev;
+
+/*
+ * Theory of operation
+ *
+ * The Au1000 MACs use a simple rx and tx descriptor ring scheme. 
+ * There are four receive and four transmit descriptors.  These 
+ * descriptors are not in memory; rather, they are just a set of 
+ * hardware registers.
+ *
+ * Since the Au1000 has a coherent data cache, the receive and
+ * transmit buffers are allocated from the KSEG0 segment. The 
+ * hardware registers, however, are still mapped at KSEG1 to
+ * make sure there's no out-of-order writes, and that all writes
+ * complete immediately.
+ */
+
+
+/*
+ * Base address and interupt of the Au1000 ethernet macs
+ */
+static struct {
+	unsigned int port;
+	int irq;
+} au1000_iflist[NUM_INTERFACES] = {
+	{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 
+	{AU1000_ETH1_BASE, AU1000_ETH1_IRQ}
+};
+
+
+static char version[] __devinitdata =
+    "au1000eth.c:0.1 ppopov@mvista.com\n";
+
+// FIX! Need real Ethernet addresses
+static unsigned char au1000_mac_addr[2][6] __devinitdata = { 
+	{0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00},
+	{0x00, 0x50, 0xc2, 0x0c, 0x40, 0x00}
+};
+
+#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))
+#define RUN_AT(x) (jiffies + (x))
+
+// For reading/writing 32-bit words from/to DMA memory
+#define cpu_to_dma32 cpu_to_be32
+#define dma32_to_cpu be32_to_cpu
+
+/* CPU pipeline flush */
+static inline void sync(void)
+{
+	asm volatile ("sync");
+}
+
+/* FIXME 
+ * All of the PHY code really should be detached from the MAC 
+ * code.
+ */
+
+static char *phy_link[] = 
+	{"unknown", 
+	"10Base2", "10BaseT", 
+	"AUI",
+	"100BaseT", "100BaseTX", "100BaseFX"};
+
+int bcm_5201_init(struct net_device *dev, int phy_addr)
+{
+	s16 data;
+	
+	/* Stop auto-negotiation */
+	//printk("bcm_5201_init\n");
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
+
+	/* Set advertisement to 10/100 and Half/Full duplex
+	 * (full capabilities) */
+	data = mdio_read(dev, phy_addr, MII_ANADV);
+	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
+	mdio_write(dev, phy_addr, MII_ANADV, data);
+	
+	/* Restart auto-negotiation */
+	data = mdio_read(dev, phy_addr, MII_CONTROL);
+	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
+	mdio_write(dev, phy_addr, MII_CONTROL, data);
+	//dump_mii(dev, phy_addr);
+	return 0;
+}
+
+int bcm_5201_reset(struct net_device *dev, int phy_addr)
+{
+	s16 mii_control, timeout;
+	
+	//printk("bcm_5201_reset\n");
+	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
+	mdelay(1);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
+		if ((mii_control & MII_CNTL_RESET) == 0)
+			break;
+		mdelay(1);
+	}
+	if (mii_control & MII_CNTL_RESET) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
+
+int 
+bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	u16 mii_data;
+	struct au1000_private *aup;
+
+	if (!dev) {
+		printk(KERN_ERR "bcm_5201_status error: NULL dev\n");
+		return -1;
+	}
+	aup = (struct au1000_private *) dev->priv;
+
+	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
+	if (mii_data & MII_STAT_LINK) {
+		*link = 1;
+		mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
+		if (mii_data & MII_AUX_100) {
+			if (mii_data & MII_AUX_FDX) {
+				*speed = IF_PORT_100BASEFX;
+				dev->if_port = IF_PORT_100BASEFX;
+			}
+			else {
+				*speed = IF_PORT_100BASETX;
+				dev->if_port = IF_PORT_100BASETX;
+			}
+		}
+		else  {
+			*speed = IF_PORT_10BASET;
+			dev->if_port = IF_PORT_10BASET;
+		}
+
+	}
+	else {
+		*link = 0;
+		*speed = 0;
+	}
+	return 0;
+}
+
+
+int am79c901_init(struct net_device *dev, int phy_addr)
+{
+	printk("am79c901_init\n");
+	return 0;
+}
+
+int am79c901_reset(struct net_device *dev, int phy_addr)
+{
+	printk("am79c901_reset\n");
+	return 0;
+}
+
+int 
+am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
+{
+	return 0;
+}
+
+struct phy_ops bcm_5201_ops = {
+	bcm_5201_init,
+	bcm_5201_reset,
+	bcm_5201_status,
+};
+
+struct phy_ops am79c901_ops = {
+	am79c901_init,
+	am79c901_reset,
+	am79c901_status,
+};
+
+static struct mii_chip_info {
+	const char * name;
+	u16 phy_id0;
+	u16 phy_id1;
+	struct phy_ops *phy_ops;	
+} mii_chip_table[] = {
+	{"Broadcom BCM5201 10/100 BaseT PHY",  0x0040, 0x6212, &bcm_5201_ops },
+	{"AMD 79C901 HomePNA PHY",  0x0000, 0x35c8, &am79c901_ops },
+	{0,},
+};
+
+static int mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	u32 timedout = 20;
+	u32 mii_control;
+
+	while (aup->mac->mii_control & MAC_MII_BUSY) {
+		mdelay(1);
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: read_MII busy timeout!!\n", dev->name);
+			return -1;
+		}
+	}
+
+	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
+		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ;
+
+	aup->mac->mii_control = mii_control;
+
+	timedout = 20;
+	while (aup->mac->mii_control & MAC_MII_BUSY) {
+		mdelay(1);
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: mdio_read busy timeout!!\n", dev->name);
+			return -1;
+		}
+	}
+	return (int)aup->mac->mii_data;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	u32 timedout = 20;
+	u32 mii_control;
+
+	while (aup->mac->mii_control & MAC_MII_BUSY) {
+		mdelay(1);
+		if (--timedout == 0) {
+			printk(KERN_ERR "%s: mdio_write busy timeout!!\n", dev->name);
+			return;
+		}
+	}
+
+	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
+		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE;
+
+	aup->mac->mii_data = value;
+	aup->mac->mii_control = mii_control;
+}
+
+
+static void dump_mii(struct net_device *dev, int phy_id)
+{
+	int i, val;
+
+	for (i = 0; i < 7; i++) {
+		if ((val = mdio_read(dev, phy_id, i)) >= 0)
+			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+	}
+	for (i = 16; i < 25; i++) {
+		if ((val = mdio_read(dev, phy_id, i)) >= 0)
+			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+	}
+}
+
+static int __init mii_probe (struct net_device * dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	int phy_addr;
+
+	aup->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(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(dev, phy_addr, MII_PHY_ID0);
+		phy_id1 = mdio_read(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 &&
+			    phy_id1 == mii_chip_table[i].phy_id1) {
+				struct mii_phy * mii_phy;
+
+				printk(KERN_INFO "%s: %s found at phy address %d\n",
+				       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(dev, phy_addr, MII_STATUS);
+					mii_phy->next = aup->mii;
+					aup->phy_ops = mii_chip_table[i].phy_ops;
+					aup->mii = mii_phy;
+				}
+				/* the current mii is on our mii_info_table,
+				   try next address */
+				break;
+			}
+	}
+
+	if (aup->mii == NULL) {
+		printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name);
+		return -1;
+	}
+
+	/* use last PHY */
+	aup->phy_addr = aup->mii->phy_addr;
+	printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name);
+
+	return 0;
+}
+
+
+/*
+ * Buffer allocation/deallocation routines. The buffer descriptor returned
+ * has the virtual and dma address of a buffer suitable for 
+ * both, receive and transmit operations.
+ */
+static db_dest_t *GetFreeDB(struct au1000_private *aup)
+{
+	db_dest_t *pDB;
+	pDB = aup->pDBfree;
+
+	if (pDB) {
+		aup->pDBfree = pDB->pnext;
+	}
+	//printk("GetFreeDB: %x\n", pDB);
+	return pDB;
+}
+
+void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
+{
+	db_dest_t *pDBfree = aup->pDBfree;
+	if (pDBfree)
+		pDBfree->pnext = pDB;
+	aup->pDBfree = pDB;
+}
+
+
+/*
+  DMA memory allocation, derived from pci_alloc_consistent.
+  However, the Au1000 data cache is coherent (when programmed
+  so), therefore we return KSEG0 address, not KSEG1.
+*/
+static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
+{
+	void *ret;
+	int gfp = GFP_ATOMIC | GFP_DMA;
+
+	ret = (void *) __get_free_pages(gfp, get_order(size));
+
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_bus(ret);
+		ret = KSEG0ADDR(ret);
+	}
+	return ret;
+}
+
+
+static void dma_free(void *vaddr, size_t size)
+{
+	vaddr = KSEG0ADDR(vaddr);
+	free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+static void hard_stop(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	if (au1000_debug > 4)
+		printk(KERN_INFO "%s: hard stop\n", dev->name);
+
+	aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
+	sync();
+	mdelay(10);
+}
+
+
+static void reset_mac(struct net_device *dev)
+{
+	u32 flags;
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	if (au1000_debug > 4)
+		printk(KERN_INFO "%s: reset mac, aup %x\n", dev->name, (unsigned)aup);
+
+	spin_lock_irqsave(&aup->lock, flags);
+	del_timer(&aup->timer);
+	hard_stop(dev);
+	*aup->enable |= MAC_DMA_RESET;
+	sync();
+	mdelay(10);
+	aup->tx_full = 0;
+	spin_unlock_irqrestore(&aup->lock, flags);
+}
+
+static void cleanup_buffers(struct net_device *dev)
+{
+	int i;
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	for (i=0; i<NUM_RX_DMA; i++) {
+		if (aup->rx_db_inuse[i]) {
+			ReleaseDB(aup, aup->rx_db_inuse[i]);
+			aup->rx_db_inuse[i] = 0;
+		}
+	}
+
+	for (i=0; i<NUM_TX_DMA; i++) {
+		if (aup->tx_db_inuse[i]) {
+			ReleaseDB(aup, aup->tx_db_inuse[i]);
+			aup->tx_db_inuse[i] = 0;
+		}
+	}
+}
+
+
+/* 
+ * Setup the receive and transmit "rings".  These pointers are the addresses
+ * of the rx and tx MAC DMA registers so they are fixed by the hardware --
+ * these are not descriptors sitting in memory.
+ */
+static void 
+setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
+{
+	int i;
+
+	for (i=0; i<NUM_RX_DMA; i++) {
+		aup->rx_dma_ring[i] = (volatile rx_dma_t *) ioremap_nocache((unsigned long)
+					(rx_base + sizeof(rx_dma_t)*i), sizeof(rx_dma_t));
+	}
+	for (i=0; i<NUM_TX_DMA; i++) {
+		aup->tx_dma_ring[i] = (volatile tx_dma_t *)ioremap_nocache((unsigned long)
+				(tx_base + sizeof(tx_dma_t)*i), sizeof(tx_dma_t));
+	}
+}
+
+/*
+ * Probe for a AU1000 ethernet controller.
+ */
+int __init au1000_probe(struct net_device *dev)
+{
+	int base_addr = au1000_iflist[next_dev].port;
+	int irq = au1000_iflist[next_dev].irq;
+
+#ifndef CONFIG_MIPS_AU1000_ENET
+	return -ENODEV;
+#endif
+
+	if (au1000_debug > 4)
+		printk(KERN_INFO "%s: au1000_probe base_addr %x\n", 
+				dev->name, base_addr);
+
+	if (next_dev >= NUM_INTERFACES) {
+		return -ENODEV;
+	}
+	if (au1000_probe1(dev, base_addr, irq, next_dev) == 0) {
+		next_dev++;
+		return 0;
+	}
+	next_dev++;
+	return -ENODEV;
+}
+
+
+
+static int __init
+au1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num)
+{
+	static unsigned version_printed = 0;
+	struct au1000_private *aup = NULL;
+	int i, retval = 0;
+	db_dest_t *pDB, *pDBfree;
+	u16 link, speed;
+
+	if ((ioaddr != AU1000_ETH0_BASE) && (ioaddr != AU1000_ETH1_BASE))  {
+		return -ENODEV;
+	}
+
+	if (!request_region(ioaddr, MAC_IOSIZE, "Au1000 ENET")) {
+		 return -ENODEV;
+	}
+
+	if (version_printed++ == 0) printk(version);
+
+	if (!dev) {
+		dev = init_etherdev(0, sizeof(struct au1000_private));
+	}
+	if (!dev) {
+		 printk (KERN_ERR "au1000 eth: init_etherdev failed\n");  
+		 return -ENODEV;
+	}
+
+	printk("%s: Au1000 ethernet found at 0x%lx, irq %d\n",
+	       dev->name, ioaddr, irq);
+
+
+	/* Initialize our private structure */
+	if (dev->priv == NULL) {
+		aup = (struct au1000_private *) kmalloc(sizeof(*aup), GFP_KERNEL);
+		if (aup == NULL) {
+			retval = -ENOMEM;
+			goto free_region;
+		}
+		dev->priv = aup;
+	}
+
+	aup = dev->priv;
+	memset(aup, 0, sizeof(*aup));
+
+
+	/* Allocate the data buffers */
+	aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr);
+	if (!aup->vaddr) {
+		retval = -ENOMEM;
+		goto free_region;
+	}
+
+	/* aup->mac is the base address of the MAC's registers */
+	aup->mac = (volatile mac_reg_t *)ioremap_nocache((unsigned long)ioaddr, sizeof(*aup->mac));
+	/* Setup some variables for quick register address access */
+	if (ioaddr == AU1000_ETH0_BASE) {
+		aup->enable = (volatile u32 *)
+			ioremap_nocache((unsigned long)MAC0_ENABLE, sizeof(*aup->enable)); 
+		memcpy(dev->dev_addr, au1000_mac_addr[0], sizeof(dev->dev_addr));
+		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
+	}
+	else if (ioaddr == AU1000_ETH1_BASE) {
+		aup->enable = (volatile u32 *)
+			ioremap_nocache((unsigned long)MAC1_ENABLE, sizeof(*aup->enable)); 
+		memcpy(dev->dev_addr, au1000_mac_addr[1], sizeof(dev->dev_addr));
+		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
+	}
+	else { /* should never happen */
+		 printk (KERN_ERR "au1000 eth: bad ioaddr %x\n", (unsigned)ioaddr);  
+		 retval = -ENODEV;
+		 goto free_region;
+	}
+
+	aup->phy_addr = PHY_ADDRESS;
+	/* bring the device out of reset, otherwise probing the mii
+	 * will hang */
+	*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 |
+		MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS;
+	sync();
+	mdelay(2);
+	if (mii_probe(dev) != 0) {
+		 goto free_region;
+	}
+	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
+	if (!link) {
+		printk(KERN_INFO "%s: link down resetting...\n", dev->name);
+		aup->phy_ops->phy_reset(dev, aup->phy_addr);
+		aup->phy_ops->phy_init(dev, aup->phy_addr);
+	}
+	else {
+		printk(KERN_INFO "%s: link up (%s)\n", dev->name, phy_link[speed]);
+	}
+
+	pDBfree = NULL;
+	/* setup the data buffer descriptors and attach a buffer to each one */
+	pDB = aup->db;
+	for (i=0; i<(NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
+		pDB->pnext = pDBfree;
+		pDBfree = pDB;
+		pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i);
+		pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
+		pDB++;
+	}
+	aup->pDBfree = pDBfree;
+
+	for (i=0; i<NUM_RX_DMA; i++) {
+		pDB = GetFreeDB(aup);
+		if (!pDB) goto free_region;
+		aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
+		aup->rx_db_inuse[i] = pDB;
+	}
+	for (i=0; i<NUM_TX_DMA; i++) {
+		pDB = GetFreeDB(aup);
+		if (!pDB) goto free_region;
+		aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
+		aup->tx_dma_ring[i]->len = 0;
+		aup->tx_db_inuse[i] = pDB;
+	}
+
+	spin_lock_init(&aup->lock);
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->open = au1000_open;
+	dev->hard_start_xmit = au1000_tx;
+	dev->stop = au1000_close;
+	dev->get_stats = au1000_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &au1000_ioctl;
+	dev->set_config = &au1000_set_config;
+	dev->tx_timeout = au1000_tx_timeout;
+	dev->watchdog_timeo = ETH_TX_TIMEOUT;
+
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	/* 
+	 * The boot code uses the ethernet controller, so reset it to start fresh.
+	 * au1000_init() expects that the device is in reset state.
+	 */
+	reset_mac(dev);
+
+	return 0;
+
+free_region:
+	release_region(ioaddr, MAC_IOSIZE);
+	unregister_netdev(dev);
+	if (aup->vaddr)
+		dma_free((void *)aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS));
+	if (dev->priv != NULL)
+		kfree(dev->priv);
+	kfree(dev);
+	printk(KERN_ERR "%s: au1000_probe1 failed.  Returns %d\n",
+	       dev->name, retval);
+	return retval;
+}
+
+
+/* 
+ * Initialize the interface.
+ *
+ * When the device powers up, the clocks are disabled and the
+ * mac is in reset state.  When the interface is closed, we
+ * do the same -- reset the device and disable the clocks to
+ * conserve power. Thus, whenever au1000_init() is called,
+ * the device should already be in reset state.
+ */
+static int au1000_init(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	u32 flags;
+	int i;
+	u32 value, control;
+
+	if (au1000_debug > 4) printk("%s: au1000_init", dev->name);
+
+	spin_lock_irqsave(&aup->lock, flags);
+
+	/* bring the device out of reset */
+	value = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 |
+		MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS;
+	*aup->enable = value;
+	sync();
+	mdelay(200);
+
+	aup->mac->control = 0;
+	aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
+	aup->tx_tail = aup->tx_head;
+	aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2;
+
+	aup->mac->mac_addr_high = dev->dev_addr[5]<<8 | dev->dev_addr[4];
+	aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
+		dev->dev_addr[1]<<8 | dev->dev_addr[0];
+
+	for (i=0; i<NUM_RX_DMA; i++) {
+		aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
+	}
+
+	sync();
+	control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
+#ifndef CONFIG_CPU_LITTLE_ENDIAN
+	control |= MAC_BIG_ENDIAN;
+#endif
+	aup->mac->control = control;
+
+	spin_unlock_irqrestore(&aup->lock, flags);
+	return 0;
+}
+
+static void au1000_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	u16 mii_data, link, speed;
+
+	if (!dev) {
+		/* fatal error, don't restart the timer */
+		printk(KERN_ERR "au1000_timer error: NULL dev\n");
+		return;
+	}
+	if (!(dev->flags & IFF_UP)) {
+		goto set_timer;
+	}
+
+	if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) {
+		if (link) {
+			if (!(dev->flags & IFF_RUNNING)) {
+				netif_carrier_on(dev);
+				dev->flags |= IFF_RUNNING;
+				printk(KERN_DEBUG "%s: link up\n", dev->name);
+			}
+		}
+		else {
+			if (dev->flags & IFF_RUNNING) {
+				netif_carrier_off(dev);
+				dev->flags &= ~IFF_RUNNING;
+				dev->if_port = 0;
+				printk(KERN_DEBUG "%s: link down\n", dev->name);
+			}
+		}
+	}
+
+set_timer:
+	aup->timer.expires = RUN_AT((1*HZ)); 
+	aup->timer.data = (unsigned long)dev;
+	aup->timer.function = &au1000_timer; /* timer handler */
+	add_timer(&aup->timer);
+
+}
+
+static int au1000_open(struct net_device *dev)
+{
+	int retval;
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	MOD_INC_USE_COUNT;
+
+	if (au1000_debug > 4)
+		printk("%s: open: dev=%p\n", dev->name, dev);
+
+	if ((retval = au1000_init(dev))) {
+		printk(KERN_ERR "%s: error in au1000_init\n", dev->name);
+		free_irq(dev->irq, dev);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	netif_start_queue(dev);
+
+	if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, dev->name, dev))) {
+		printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	aup->timer.expires = RUN_AT((3*HZ)); 
+	aup->timer.data = (unsigned long)dev;
+	aup->timer.function = &au1000_timer; /* timer handler */
+	add_timer(&aup->timer);
+
+	if (au1000_debug > 4)
+		printk("%s: open: Initialization done.\n", dev->name);
+
+	return 0;
+}
+
+static int au1000_close(struct net_device *dev)
+{
+	u32 flags;
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	if (au1000_debug > 4)
+		printk("%s: close: dev=%p\n", dev->name, dev);
+
+	spin_lock_irqsave(&aup->lock, flags);
+	
+	/* stop the device */
+	if (netif_device_present(dev)) {
+		netif_stop_queue(dev);
+	}
+
+	/* disable the interrupt */
+	free_irq(dev->irq, dev);
+	spin_unlock_irqrestore(&aup->lock, flags);
+
+	reset_mac(dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static inline void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct net_device_stats *ps = &aup->stats;
+
+	ps->tx_packets++;
+	ps->tx_bytes += pkt_len;
+
+	if (status & TX_FRAME_ABORTED) {
+		ps->tx_errors++;
+		ps->tx_aborted_errors++;
+		if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER))
+			ps->tx_carrier_errors++;
+	}
+}
+
+
+/*
+ * Called from the interrupt service routine to acknowledge
+ * the TX DONE bits.  This is a must if the irq is setup as
+ * edge triggered.
+ */
+static void au1000_tx_ack(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	volatile tx_dma_t *ptxd;
+
+	ptxd = aup->tx_dma_ring[aup->tx_tail];
+
+	while (ptxd->buff_stat & TX_T_DONE) {
+		update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
+		ptxd->buff_stat &= ~TX_T_DONE;
+		ptxd->len = 0;
+		sync();
+
+		aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);
+		ptxd = aup->tx_dma_ring[aup->tx_tail];
+
+		if (aup->tx_full) {
+			aup->tx_full = 0;
+			netif_wake_queue(dev);
+		}
+	}
+}
+
+
+/*
+ * Au1000 transmit routine.
+ */
+static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	//unsigned long flags;
+	volatile tx_dma_t *ptxd;
+	u32 buff_stat;
+	db_dest_t *pDB;
+	int i;
+
+	if (au1000_debug > 4)
+		printk("%s: tx: aup %x len=%d, data=%p, head %d\n",
+		       dev->name, (unsigned)aup, skb->len, skb->data, aup->tx_head);
+
+	/* Prevent interrupts from changing the Tx ring */
+	//spin_lock_irqsave(&aup->lock, flags);
+	
+	ptxd = aup->tx_dma_ring[aup->tx_head];
+	buff_stat = ptxd->buff_stat;
+	if (buff_stat & TX_DMA_ENABLE) {
+		/* We've wrapped around and the transmitter is still busy */
+		netif_stop_queue(dev);
+		aup->tx_full = 1;
+		//spin_unlock_irqrestore(&aup->lock, flags);
+		return 1;
+	}
+	else if (buff_stat & TX_T_DONE) {
+		update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
+		ptxd->len = 0;
+	}
+
+	if (aup->tx_full) {
+		aup->tx_full = 0;
+		netif_wake_queue(dev);
+	}
+
+	pDB = aup->tx_db_inuse[aup->tx_head];
+	memcpy((void *)pDB->vaddr, skb->data, skb->len);
+	if (skb->len < MAC_MIN_PKT_SIZE) {
+		for (i=skb->len; i<MAC_MIN_PKT_SIZE; i++) { 
+			((char *)pDB->vaddr)[i] = 0;
+		}
+		ptxd->len = MAC_MIN_PKT_SIZE;
+	}
+	else
+		ptxd->len = skb->len;
+
+	ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
+	sync();
+	dev_kfree_skb(skb);
+	aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
+	dev->trans_start = jiffies;
+	//spin_unlock_irqrestore(&aup->lock, flags);
+	return 0;
+}
+
+
+static inline void update_rx_stats(struct net_device *dev, u32 status)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct net_device_stats *ps = &aup->stats;
+
+	ps->rx_packets++;
+	if (status & RX_MCAST_FRAME)
+		ps->multicast++;
+
+	if (status & RX_ERROR) {
+		ps->rx_errors++;
+		if (status & RX_MISSED_FRAME)
+			ps->rx_missed_errors++;
+		if (status & (RX_OVERLEN | RX_OVERLEN | RX_LEN_ERROR))
+			ps->rx_length_errors++;
+		if (status & RX_CRC_ERROR)
+			ps->rx_crc_errors++;
+		if (status & RX_COLL)
+			ps->collisions++;
+	}
+	else 
+		ps->rx_bytes += status & RX_FRAME_LEN_MASK;
+
+}
+
+/*
+ * Au1000 receive routine.
+ */
+static int au1000_rx(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct sk_buff *skb;
+	volatile rx_dma_t *prxd;
+	u32 buff_stat, status;
+	db_dest_t *pDB;
+
+	if (au1000_debug > 4)
+		printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);
+
+	prxd = aup->rx_dma_ring[aup->rx_head];
+	buff_stat = prxd->buff_stat;
+	while (buff_stat & RX_T_DONE)  {
+		status = prxd->status;
+		pDB = aup->rx_db_inuse[aup->rx_head];
+		update_rx_stats(dev, status);
+		if (!(status & RX_ERROR))  {
+
+			/* good frame */
+			skb = dev_alloc_skb((status & RX_FRAME_LEN_MASK) + 2);
+			if (skb == NULL) {
+				printk(KERN_ERR
+				       "%s: Memory squeeze, dropping packet.\n",
+				       dev->name);
+				aup->stats.rx_dropped++;
+				continue;
+			}
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte IP header align */
+			eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, 
+					status & RX_FRAME_LEN_MASK, 0);
+			skb_put(skb, status & RX_FRAME_LEN_MASK); /* Make room */
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);	/* pass the packet to upper layers */
+		}
+		else {
+			if (au1000_debug > 4) {
+				if (status & RX_MISSED_FRAME) 
+					printk("rx miss\n");
+				if (status & RX_WDOG_TIMER) 
+					printk("rx wdog\n");
+				if (status & RX_RUNT) 
+					printk("rx runt\n");
+				if (status & RX_OVERLEN) 
+					printk("rx overlen\n");
+				if (status & RX_COLL)
+					printk("rx coll\n");
+				if (status & RX_MII_ERROR)
+					printk("rx mii error\n");
+				if (status & RX_CRC_ERROR)
+					printk("rx crc error\n");
+				if (status & RX_LEN_ERROR)
+					printk("rx len error\n");
+				if (status & RX_U_CNTRL_FRAME)
+					printk("rx u control frame\n");
+				if (status & RX_MISSED_FRAME)
+					printk("rx miss\n");
+			}
+		}
+		prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
+		aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1);
+		sync();
+
+		/* next descriptor */
+		prxd = aup->rx_dma_ring[aup->rx_head];
+		buff_stat = prxd->buff_stat;
+		dev->last_rx = jiffies;
+	}
+	return 0;
+}
+
+
+/*
+ * Au1000 interrupt service routine.
+ */
+void au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+
+	if (dev == NULL) {
+		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
+		return;
+	}
+	au1000_rx(dev);
+	au1000_tx_ack(dev);
+}
+
+
+/*
+ * The Tx ring has been full longer than the watchdog timeout
+ * value. The transmitter must be hung?
+ */
+static void au1000_tx_timeout(struct net_device *dev)
+{
+	printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev);
+	reset_mac(dev);
+	au1000_init(dev);
+}
+
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+    int crc = -1;
+
+    while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^
+				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+    }
+    return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	/* fixme */
+	if (au1000_debug > 4) 
+		printk("%s: set_multicast: flags=%x\n", dev->name, dev->flags);
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		aup->mac->control |= MAC_PROMISCUOUS;
+		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+	} else if ((dev->flags & IFF_ALLMULTI)  ||
+			   dev->mc_count > MULTICAST_FILTER_LIMIT) {
+		aup->mac->control |= MAC_PASS_ALL_MULTI;
+		aup->mac->control &= ~MAC_PROMISCUOUS;
+		printk(KERN_INFO "%s: Pass all multicast\n", dev->name);
+	} else {
+		int i;
+		struct dev_mc_list *mclist;
+		u32 mc_filter[2];	/* Multicast hash filter */
+
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+		}
+		aup->mac->multi_hash_high = mc_filter[1];
+		aup->mac->multi_hash_low = mc_filter[0];
+		aup->mac->control |= MAC_HASH_MODE;
+	}
+}
+
+
+static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	//struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
+
+	/* fixme */
+	switch(cmd) { 
+		case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = PHY_ADDRESS;
+		case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		//data[3] = mdio_read(ioaddr, data[0], data[1]); 
+		return 0;
+		case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		//mdio_write(ioaddr, data[0], data[1], data[2]);
+		return 0;
+		default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
+static int au1000_set_config(struct net_device *dev, struct ifmap *map)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	u16 control;
+
+	if (au1000_debug > 4)  {
+		printk("%s: set_config called: dev->if_port %d map->port %x\n", 
+				dev->name, dev->if_port, map->port);
+	}
+
+	switch(map->port){
+		case IF_PORT_UNKNOWN: /* use auto here */   
+			printk("auto\\n");
+			dev->if_port = map->port;
+			/* Link Down: the timer will bring it up */
+			netif_carrier_off(dev);
+	
+			/* read current control */
+			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
+			control &= ~(MII_CNTL_FDX | MII_CNTL_F100);
+
+			/* enable auto negotiation and reset the negotiation */
+			mdio_write(dev, aup->phy_addr,
+				   MII_CONTROL, control | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+
+			break;
+    
+		case IF_PORT_10BASET: /* 10BaseT */         
+			printk("10baseT\n");
+			dev->if_port = map->port;
+	
+			/* Link Down: the timer will bring it up */
+			netif_carrier_off(dev);
+
+			/* set Speed to 10Mbps, Half Duplex */
+			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
+			printk("read control %x\n", control);
+			control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_FDX);
+	
+			/* disable auto negotiation and force 10M/HD mode*/
+			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
+			break;
+    
+		case IF_PORT_100BASET: /* 100BaseT */
+		case IF_PORT_100BASETX: /* 100BaseTx */ 
+			printk("100 base T/TX\n");
+			dev->if_port = map->port;
+	
+			/* Link Down: the timer will bring it up */
+			netif_carrier_off(dev);
+	
+			/* set Speed to 100Mbps, Half Duplex */
+			/* disable auto negotiation and enable 100MBit Mode */
+			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
+			printk("read control %x\n", control);
+			control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX);
+			control |= MII_CNTL_F100;
+			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
+			break;
+    
+		case IF_PORT_100BASEFX: /* 100BaseFx */
+			printk("100 Base FX\n");
+			dev->if_port = map->port;
+	
+			/* Link Down: the timer will bring it up */
+			netif_carrier_off(dev);
+	
+			/* set Speed to 100Mbps, Full Duplex */
+			/* disable auto negotiation and enable 100MBit Mode */
+			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
+			control &= ~MII_CNTL_AUTO;
+			control |=  MII_CNTL_F100 | MII_CNTL_FDX;
+			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
+			break;
+		case IF_PORT_10BASE2: /* 10Base2 */
+		case IF_PORT_AUI: /* AUI */
+		/* These Modes are not supported (are they?)*/
+			printk(KERN_INFO "Not supported");
+			return -EOPNOTSUPP;
+			break;
+    
+		default:
+			printk("Invalid");
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static struct net_device_stats *au1000_get_stats(struct net_device *dev)
+{
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	if (au1000_debug > 4)
+		printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev);
+
+	if (netif_device_present(dev)) {
+		return &aup->stats;
+	}
+	return 0;
+}
diff -u --recursive --new-file v2.4.6/linux/drivers/net/au1000_eth.h linux/drivers/net/au1000_eth.h
--- v2.4.6/linux/drivers/net/au1000_eth.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/au1000_eth.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,223 @@
+/*
+ *
+ * Alchemy Semi Au1000 ethernet driver include file
+ *
+ * Author: Pete Popov <ppopov@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * ########################################################################
+ *
+ * 
+ */
+
+
+#define NUM_INTERFACES 2
+#define MAC_IOSIZE 0x10000
+#define NUM_RX_DMA 4       /* Au1000 has 4 rx hardware descriptors */
+#define NUM_TX_DMA 4       /* Au1000 has 4 tx hardware descriptors */
+
+#define NUM_RX_BUFFS 4
+#define NUM_TX_BUFFS 4
+#define MAX_BUF_SIZE 2048
+
+#define ETH_TX_TIMEOUT HZ/4
+#define MAC_MIN_PKT_SIZE 64
+
+#ifdef CONFIG_MIPS_PB1000
+#define PHY_ADDRESS              0
+#define PHY_CONTROL_DEFAULT 0x3000
+#define PHY_CONTROL_REG_ADDR     0
+#endif
+
+#define MULTICAST_FILTER_LIMIT 64
+
+/* FIXME 
+ * The PHY defines should be in a separate file.
+ */
+
+/* MII register offsets */
+#define	MII_CONTROL 0x0000
+#define MII_STATUS  0x0001
+#define MII_PHY_ID0 0x0002
+#define	MII_PHY_ID1 0x0003
+#define MII_ANADV   0x0004
+#define MII_ANLPAR  0x0005
+#define MII_AEXP    0x0006
+#define MII_ANEXT   0x0007
+#define MII_AUX_CNTRL 0x18
+
+/* mii registers specific to AMD 79C901 */
+#define	MII_STATUS_SUMMARY = 0x0018
+
+/* MII Control register bit definitions. */
+#define	MII_CNTL_FDX      0x0100
+#define MII_CNTL_RST_AUTO 0x0200
+#define	MII_CNTL_ISOLATE  0x0400
+#define MII_CNTL_PWRDWN   0x0800
+#define	MII_CNTL_AUTO     0x1000
+#define MII_CNTL_F100     0x2000
+#define	MII_CNTL_LPBK     0x4000
+#define MII_CNTL_RESET    0x8000
+
+/* MII Status register bit  */
+#define	MII_STAT_EXT        0x0001 
+#define MII_STAT_JAB        0x0002
+#define	MII_STAT_LINK       0x0004
+#define MII_STAT_CAN_AUTO   0x0008
+#define	MII_STAT_FAULT      0x0010 
+#define MII_STAT_AUTO_DONE  0x0020
+#define	MII_STAT_CAN_T      0x0800
+#define MII_STAT_CAN_T_FDX  0x1000
+#define	MII_STAT_CAN_TX     0x2000 
+#define MII_STAT_CAN_TX_FDX 0x4000
+#define	MII_STAT_CAN_T4     0x8000
+
+
+#define		MII_ID1_OUI_LO		0xFC00	/* low bits of OUI mask */
+#define		MII_ID1_MODEL		0x03F0	/* model number */
+#define		MII_ID1_REV		0x000F	/* model number */
+
+/* MII NWAY Register Bits ...
+   valid for the ANAR (Auto-Negotiation Advertisement) and
+   ANLPAR (Auto-Negotiation Link Partner) registers */
+#define	MII_NWAY_NODE_SEL 0x001f
+#define MII_NWAY_CSMA_CD  0x0001
+#define	MII_NWAY_T	  0x0020
+#define MII_NWAY_T_FDX    0x0040
+#define	MII_NWAY_TX       0x0080
+#define MII_NWAY_TX_FDX   0x0100
+#define	MII_NWAY_T4       0x0200 
+#define MII_NWAY_PAUSE    0x0400 
+#define	MII_NWAY_RF       0x2000 /* Remote Fault */
+#define MII_NWAY_ACK      0x4000 /* Remote Acknowledge */
+#define	MII_NWAY_NP       0x8000 /* Next Page (Enable) */
+
+/* mii stsout register bits */
+#define	MII_STSOUT_LINK_FAIL 0x4000
+#define	MII_STSOUT_SPD       0x0080
+#define MII_STSOUT_DPLX      0x0040
+
+/* mii stsics register bits */
+#define	MII_STSICS_SPD       0x8000
+#define MII_STSICS_DPLX      0x4000
+#define	MII_STSICS_LINKSTS   0x0001
+
+/* mii stssum register bits */
+#define	MII_STSSUM_LINK  0x0008
+#define MII_STSSUM_DPLX  0x0004
+#define	MII_STSSUM_AUTO  0x0002
+#define MII_STSSUM_SPD   0x0001
+
+/* Auxilliary Control/Status Register */
+#define MII_AUX_FDX      0x0001
+#define MII_AUX_100      0x0002
+#define MII_AUX_F100     0x0004
+#define MII_AUX_ANEG     0x0008
+
+typedef struct mii_phy {
+	struct mii_phy * next;
+	struct mii_chip_info * chip_info;
+	int phy_addr;
+	u16 status;
+} mii_phy_t;
+
+struct phy_ops {
+	int (*phy_init) (struct net_device *, int);
+	int (*phy_reset) (struct net_device *, int);
+	int (*phy_status) (struct net_device *, int, u16 *, u16 *);
+};
+
+/* 
+ * Data Buffer Descriptor. Data buffers must be aligned on 32 byte 
+ * boundary for both, receive and transmit.
+ */
+typedef struct db_dest {
+	struct db_dest *pnext;
+	volatile u32 *vaddr;
+	dma_addr_t dma_addr;
+} db_dest_t;
+
+/*
+ * The transmit and receive descriptors are memory 
+ * mapped registers.
+ */
+typedef struct tx_dma {
+	u32 status;
+	u32 buff_stat;
+	u32 len;
+	u32 pad;
+} tx_dma_t;
+
+typedef struct rx_dma {
+	u32 status;
+	u32 buff_stat;
+	u32 pad[2];
+} rx_dma_t;
+
+
+/*
+ * MAC control registers, memory mapped.
+ */
+typedef struct mac_reg {
+	u32 control;
+	u32 mac_addr_high;
+	u32 mac_addr_low;
+	u32 multi_hash_high;
+	u32 multi_hash_low;
+	u32 mii_control;
+	u32 mii_data;
+	u32 flow_control;
+	u32 vlan1_tag;
+	u32 vlan2_tag;
+} mac_reg_t;
+
+
+struct au1000_private {
+	
+	db_dest_t *pDBfree;
+	db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS];
+	volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA];
+	volatile tx_dma_t *tx_dma_ring[NUM_TX_DMA];
+	db_dest_t *rx_db_inuse[NUM_RX_DMA];
+	db_dest_t *tx_db_inuse[NUM_TX_DMA];
+	u32 rx_head;
+	u32 tx_head;
+	u32 tx_tail;
+	u32 tx_full;
+
+	mii_phy_t *mii;
+	struct phy_ops *phy_ops;
+	
+	/* These variables are just for quick access to certain regs addresses. */
+	volatile mac_reg_t *mac;  /* mac registers                      */   
+	volatile u32 *enable;     /* address of MAC Enable Register     */
+
+	u32 vaddr;                /* virtual address of rx/tx buffers   */
+	dma_addr_t dma_addr;      /* dma address of rx/tx buffers       */
+
+	u8 *hash_table;
+	u32 hash_mode;
+	u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
+	u32 phy_addr;          /* PHY address */
+	u32 options;           /* User-settable misc. driver options. */
+	u32 drv_flags;
+	struct net_device_stats stats;
+	struct timer_list timer;
+	spinlock_t lock;       /* Serialise access to device */
+};
diff -u --recursive --new-file v2.4.6/linux/drivers/net/dl2k.c linux/drivers/net/dl2k.c
--- v2.4.6/linux/drivers/net/dl2k.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/dl2k.c	Fri Jul  6 16:48:50 2001
@@ -0,0 +1,1443 @@
+/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*
+    Copyright (c) 2001 by D-Link Corporation
+    Written by Edward Peng.<edward_peng@dlink.com.tw>
+    Created 03-May-2001, base on Linux' sundance.c.
+
+    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.
+*/
+/*
+    Rev		Date		Description
+    ==========================================================================
+    0.01	2001/05/03	Create DL2000-based linux driver
+    0.02	2001/05/21	Add VLAN and hardware checksum support.
+    1.00	2001/06/26	Add jumbo frame support.
+*/
+
+#include "dl2k.h"
+
+
+static char version[] __devinitdata =
+KERN_INFO "D-Link DL2000-based linux driver v1.00 2001/06/26\n";
+
+
+
+#define MAX_UNITS 8
+static int mtu[MAX_UNITS];
+static int vlan[MAX_UNITS];
+static int jumbo[MAX_UNITS];
+static char *media[MAX_UNITS];
+static int copy_thresh;
+
+MODULE_AUTHOR ("Edward Peng");
+MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
+MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s");
+MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (jumbo, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (copy_thresh, "i");
+
+/* Enable the default interrupts */
+#define EnableInt() \
+writew(RxComplete| RxDMAComplete | HostError | IntRequested | TxComplete| \
+       TxDMAComplete| UpdateStats | LinkEvent, ioaddr + IntEnable)
+static int max_intrloop = 25;
+static int multicast_filter_limit = 0x40;
+
+static int rio_open (struct net_device *dev);
+static void tx_timeout (struct net_device *dev);
+static void alloc_list (struct net_device *dev);
+static int start_xmit (struct sk_buff *skb, struct net_device *dev);
+static void rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void tx_error (struct net_device *dev, int tx_status);
+static int receive_packet (struct net_device *dev);
+static void rio_error (struct net_device *dev, int int_status);
+static int change_mtu (struct net_device *dev, int new_mtu);
+static void set_multicast (struct net_device *dev);
+static struct net_device_stats *get_stats (struct net_device *dev);
+static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int rio_close (struct net_device *dev);
+static int find_miiphy (struct net_device *dev);
+static int parse_eeprom (struct net_device *dev);
+static int read_eeprom (long ioaddr, int eep_addr);
+static unsigned get_crc (unsigned char *p, int len);
+static int mii_wait_link (struct net_device *dev, int wait);
+static int mii_set_media (struct net_device *dev);
+static int mii_get_media (struct net_device *dev);
+static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
+static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
+		      u16 data);
+#ifdef RIO_DEBUG
+static int rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata);
+#endif
+
+static int __devinit
+rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct netdev_private *np;
+	static int card_idx;
+	int chip_idx = ent->driver_data;
+	int err, irq = pdev->irq;
+	long ioaddr;
+	static int version_printed;
+
+	if (!version_printed++)
+		printk ("%s", version);
+
+	err = pci_enable_device (pdev);
+	if (err)
+		return err;
+
+	err = pci_request_regions (pdev, "dl2k");
+	if (err)
+		goto err_out_disable;
+
+	pci_set_master (pdev);
+
+	dev = alloc_etherdev (sizeof (*np));
+	if (!dev) {
+		err = -ENOMEM;
+		goto err_out_res;
+	}
+	SET_MODULE_OWNER (dev);
+
+#ifdef USE_IO_OPS
+	ioaddr = pci_resource_start (pdev, 0);
+#else
+	ioaddr = pci_resource_start (pdev, 1);
+	ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE);
+	if (!ioaddr) {
+		err = -ENOMEM;
+		goto err_out_dev;
+	}
+#endif
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	np = dev->priv;
+	np->chip_id = chip_idx;
+	spin_lock_init (&np->lock);
+
+	/* Parse manual configuration */
+	np->an_enable = 1;
+	if (card_idx < MAX_UNITS) {
+		if (media[card_idx] != NULL) {
+			np->an_enable = 0;
+			if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+			    strcmp (media[card_idx], "4") == 0) {
+				np->speed = 100;
+				np->full_duplex = 1;
+			} else if (strcmp (media[card_idx], "100mbps_hd") == 0
+				   || strcmp (media[card_idx], "3") == 0) {
+				np->speed = 100;
+				np->full_duplex = 0;
+			} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+				   strcmp (media[card_idx], "2") == 0) {
+				np->speed = 10;
+				np->full_duplex = 1;
+			} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+				   strcmp (media[card_idx], "1") == 0) {
+				np->speed = 10;
+				np->full_duplex = 0;
+			}
+			/* Auto-Negotiation is mandatory for 1000BASE-T,
+			   IEEE 802.3ab Annex 28D page 14 */
+			else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
+				 strcmp (media[card_idx], "5") == 0 ||
+				 strcmp (media[card_idx], "1000mbps_hd") == 0 ||
+				 strcmp (media[card_idx], "6") == 0) {
+				np->speed = 1000;
+				np->full_duplex = 1;
+				np->an_enable = 1;
+			} else {
+				np->an_enable = 1;
+			}
+		}
+		if (jumbo[card_idx] != 0) {
+			np->jumbo = 1;
+			dev->mtu = 9000;
+		} else {
+			np->jumbo = 0;
+			if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
+				dev->mtu = mtu[card_idx];
+		}
+		np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
+		    vlan[card_idx] : 0;
+	}
+	dev->open = &rio_open;
+	dev->hard_start_xmit = &start_xmit;
+	dev->stop = &rio_close;
+	dev->get_stats = &get_stats;
+	dev->set_multicast_list = &set_multicast;
+	dev->do_ioctl = &rio_ioctl;
+	dev->tx_timeout = &tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->change_mtu = &change_mtu;
+#ifdef TX_HW_CHECKSUM
+	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#endif
+	pci_set_drvdata (pdev, dev);
+
+	/* Parse eeprom data */
+	parse_eeprom (dev);
+
+	/* Find PHY address */
+	err = find_miiphy (dev);
+	if (err)
+		goto err_out_unmap;
+
+	/* Set media and reset PHY */
+	mii_set_media (dev);
+
+	/* Reset all logic functions */
+	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+		ioaddr + ASICCtrl + 2);
+
+	err = register_netdev (dev);
+	if (err)
+		goto err_out_unmap;
+
+	card_idx++;
+
+	printk (KERN_INFO "%s: %s, %2x:%2x:%2x:%2x:%2x:%2x, IRQ %d\n",
+		dev->name, np->name,
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5],
+		irq);
+	return 0;
+
+err_out_unmap:
+#ifndef USE_IO_OPS
+	iounmap ((void *) ioaddr);
+
+err_out_dev:
+#endif
+	kfree (dev);
+
+err_out_res:
+	pci_release_regions (pdev);
+
+err_out_disable:
+	pci_disable_device (pdev);
+	return err;
+}
+
+int
+find_miiphy (struct net_device *dev)
+{
+	int i, phy_found = 0;
+	struct netdev_private *np;
+	long ioaddr;
+	np = dev->priv;
+	ioaddr = dev->base_addr;
+	np->phy_addr = 1;
+
+	for (i = 31; i >= 0; i--) {
+		int mii_status = mii_read (dev, i, 1);
+		if (mii_status != 0xffff && mii_status != 0x0000) {
+			np->phy_addr = i;
+			phy_found++;
+		}
+	}
+	if (!phy_found) {
+		printk (KERN_ERR "%s: No MII PHY found!\n", dev->name);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+int
+parse_eeprom (struct net_device *dev)
+{
+	int i, j;
+	int ioaddr = dev->base_addr;
+	u8 sromdata[256];
+	u8 *psib;
+	u32 crc;
+	PSROM_t psrom = (PSROM_t) sromdata;
+	struct netdev_private *np = dev->priv;
+
+	int cid, next;
+
+	/* Read eeprom */
+	for (i = 0; i < 128; i++) {
+		((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i));
+	}
+
+	/* Check CRC */
+	crc = ~get_crc (sromdata, 256 - 4);
+	if (psrom->crc != ~get_crc (sromdata, 256 - 4)) {
+		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
+		return -1;
+	}
+
+	/* Set MAC address */
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = psrom->mac_addr[i];
+
+	/* Parse Software Infomation Block */
+	i = 0x30;
+	psib = (u8 *) sromdata;
+	do {
+		cid = psib[i++];
+		next = psib[i++];
+		if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) {
+			printk (KERN_ERR "Cell data error\n");
+			return -1;
+		}
+		switch (cid) {
+		case 0:	/* Format version */
+			break;
+		case 1:	/* End of cell */
+			return 0;
+		case 2:	/* Duplex Polarity */
+			np->duplex_polarity = psib[i];
+			writeb (readb (ioaddr + PhyCtrl) | psib[i],
+				ioaddr + PhyCtrl);
+			break;
+		case 3:	/* Wake Polarity */
+			np->wake_polarity = psib[i];
+			break;
+		case 9:	/* Adapter description */
+			j = (next - i > 255) ? 255 : next - i;
+			memcpy (np->name, &(psib[i]), j);
+			break;
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		case 8:	/* Reversed */
+			break;
+		default:	/* Unknown cell */
+			return -1;
+		}
+		i = next;
+	} while (1);
+
+	return 0;
+}
+
+static int
+rio_open (struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
+	if (i)
+		return i;
+
+	/* DebugCtrl bit 4, 5, 9 must set */
+	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
+
+	/* Jumbo frame */
+	if (jumbo != 0)
+		writew (9014, ioaddr + MaxFrameSize);
+
+	alloc_list (dev);
+
+	/* Get station address */
+	for (i = 0; i < 6; i++)
+		writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);
+
+	set_multicast (dev);
+
+	/* Set RIO to poll every N*320nsec. */
+	writeb (0xff, ioaddr + RxDMAPollPeriod);
+	writeb (0xff, ioaddr + TxDMAPollPeriod);
+	netif_start_queue (dev);
+	writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
+
+	/* VLAN supported */
+	if (np->vlan) {
+		/* priority field in RxDMAIntCtrl  */
+		writel (0x7 << 10, ioaddr + RxDMAIntCtrl);
+		/* VLANId */
+		writew (np->vlan, ioaddr + VLANId);
+		/* Length/Type should be 0x8100 */
+		writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
+		/* Enable AutoVLANuntagging, but disable AutoVLANtagging.
+		   VLAN information tagged by TFC' VID, CFI fields. */
+		writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
+			ioaddr + MACCtrl);
+	}
+
+	/* Enable default interrupts */
+	EnableInt ();
+
+	/* clear statistics */
+	get_stats (dev);
+	return 0;
+}
+
+static void
+tx_timeout (struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n",
+		dev->name, readl (ioaddr + TxStatus));
+	dev->if_port = 0;
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	if (!np->tx_full)
+		netif_wake_queue (dev);
+}
+
+ /* allocate and initialize Tx and Rx descriptors */
+static void
+alloc_list (struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	np->tx_full = 0;
+	np->cur_rx = np->cur_tx = 0;
+	np->old_rx = np->old_tx = 0;
+	np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32);
+	np->rx_head_desc = &np->rx_ring[0];
+
+	/* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_skbuff[i] = 0;
+		np->tx_ring[i].status = 0;
+	}
+
+	/* Initialize Rx descriptors */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].next_desc =
+		    virt_to_le64desc (&np->rx_ring[i + 1]);
+		np->rx_ring[i].status = 0;
+		np->rx_ring[i].fraginfo = 0;
+		np->rx_skbuff[i] = 0;
+	}
+
+	/* Chain the next pointer to the top */
+	np->rx_ring[i - 1].next_desc = virt_to_le64desc (&np->rx_ring[0]);
+
+	/* Allocate the rx buffers */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		/* Allocated fixed size of skbuff */
+		struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz);
+		np->rx_skbuff[i] = skb;
+		if (skb == NULL) {
+			printk (KERN_ERR
+				"%s: alloc_list: allocate Rx buffer error! ",
+				dev->name);
+			break;
+		}
+		skb->dev = dev;	/* Mark as being used by this device. */
+		skb_reserve (skb, 2);	/* 16 byte align the IP header. */
+		/* Rubicon now supports 40 bits of addressing space. */
+		np->rx_ring[i].fraginfo = virt_to_le64desc (skb->tail);
+		np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
+	}
+
+	/* Set RFDListPtr */
+	writel (cpu_to_le32 (virt_to_bus (&np->rx_ring[0])),
+		dev->base_addr + RFDListPtr0);
+	writel (0, dev->base_addr + RFDListPtr1);
+
+	return;
+}
+
+static int
+start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	struct netdev_desc *txdesc;
+	unsigned entry;
+	u32 ioaddr;
+
+	ioaddr = dev->base_addr;
+	entry = np->cur_tx % TX_RING_SIZE;
+	np->tx_skbuff[entry] = skb;
+	txdesc = &np->tx_ring[entry];
+	txdesc->next_desc = 0;
+
+	/* Set TFDDone to avoid TxDMA gather this descriptor */
+	txdesc->status = cpu_to_le64 (TFDDone);
+	txdesc->status |=
+	    cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift));
+#ifdef TX_HW_CHECKSUM
+	if (skb->ip_summed == CHECKSUM_HW) {
+		txdesc->status |=
+		    cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
+				 IPChecksumEnable);
+	}
+#endif
+	if (np->vlan) {
+		txdesc->status |= cpu_to_le64 (VLANTagInsert |
+					       cpu_to_le64 (vlan) << 32 |
+					       cpu_to_le64 (skb->
+							    priority) << 45);
+	}
+
+	/* Send one packet each time at 10Mbps mode */
+	if (entry % 0x08 == 0 || np->speed == 10)
+		txdesc->status |= cpu_to_le64 (TxIndicate);
+	txdesc->fraginfo = virt_to_le64desc (skb->data);
+	txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48;
+
+	/* Chain the last descriptor's pointer to this one */
+	if (np->last_tx)
+		np->last_tx->next_desc = virt_to_le64desc (txdesc);
+	np->last_tx = txdesc;
+
+	/* Clear TFDDone, then TxDMA start to send this descriptor */
+	txdesc->status &= ~cpu_to_le64 (TFDDone);
+
+	DEBUG_TFD_DUMP (np);
+
+	/* TxDMAPollNow */
+	writel (readl (ioaddr + DMACtrl) | 0x00001000, ioaddr + DMACtrl);
+	np->cur_tx++;
+
+	if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) {
+		/* do nothing */
+	} else {
+		np->tx_full = 1;
+		netif_stop_queue (dev);
+	}
+
+	/* The first TFDListPtr */
+	if (readl (dev->base_addr + TFDListPtr0) == 0) {
+		writel (virt_to_bus (&np->tx_ring[entry]),
+			dev->base_addr + TFDListPtr0);
+		writel (0, dev->base_addr + TFDListPtr1);
+	}
+
+	/* NETDEV WATCHDOG timer */
+	dev->trans_start = jiffies;
+	return 0;
+}
+
+static void
+rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
+{
+	struct net_device *dev = dev_instance;
+	struct netdev_private *np;
+	unsigned int_status;
+	long ioaddr;
+	int cnt = max_intrloop;
+
+	ioaddr = dev->base_addr;
+	np = dev->priv;
+	spin_lock (&np->lock);
+	while (1) {
+		int_status = readw (ioaddr + IntStatus);
+		writew (int_status & (HostError | TxComplete | RxComplete |
+				      IntRequested | UpdateStats | LinkEvent |
+				      TxDMAComplete | RxDMAComplete | RFDListEnd
+				      | RxDMAPriority), ioaddr + IntStatus);
+		if (int_status == 0)
+			break;
+		/* Processing received packets */
+		receive_packet (dev);
+		/* TxComplete interrupt */
+		if (int_status & TxComplete) {
+			int cnt = 20;
+			int tx_status = readl (ioaddr + TxStatus);
+			while (tx_status & 0x80) {	/* TxComplete */
+				/* Handle TxError */
+				if (tx_status & 0x01)
+					tx_error (dev, tx_status);
+				tx_status = readl (ioaddr + TxStatus);
+				/* too much TxError */
+				if (--cnt < 0)
+					break;
+			}
+			/* Send one packet each time at 10Mbps mode */
+			if (np->speed == 10) {
+				np->tx_full = 0;
+				netif_wake_queue (dev);
+			}
+		}
+		/* Free used tx skbuffs */
+		for (; np->cur_tx - np->old_tx > 0; np->old_tx++) {
+			int entry = np->old_tx % TX_RING_SIZE;
+			if (!(np->tx_ring[entry].status & TFDDone))
+				break;
+			dev_kfree_skb_irq (np->tx_skbuff[entry]);
+			np->tx_skbuff[entry] = 0;
+		}
+		/* If the ring is no longer full, clear tx_full and 
+		   call netif_wake_queue() */
+		if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
+			np->tx_full = 0;
+			netif_wake_queue (dev);
+		}
+
+		/* Handle uncommon events */
+		if (int_status &
+		    (IntRequested | HostError | LinkEvent | UpdateStats))
+			rio_error (dev, int_status);
+		/* If too much interrupts here, disable all interrupts except 
+		   IntRequest. When CountDown down to 0, IntRequest will 
+		   be caught by rio_error() to recovery the interrupts */
+		if (--cnt < 0) {
+			get_stats (dev);
+			writel (1000, ioaddr + CountDown);
+			writew (IntRequested, ioaddr + IntEnable);
+			break;
+		}
+	}
+	spin_unlock (&np->lock);
+}
+
+static void
+tx_error (struct net_device *dev, int tx_status)
+{
+	struct netdev_private *np;
+	long ioaddr = dev->base_addr;
+	int frame_id;
+	int i;
+
+	np = dev->priv;
+
+	frame_id = (tx_status & 0xffff0000) >> 16;
+	printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
+		dev->name, tx_status, frame_id);
+	np->stats.tx_errors++;
+	np->stats.tx_dropped++;
+	/* Ttransmit Underrun */
+	if (tx_status & 0x10) {
+		np->stats.tx_fifo_errors++;
+		/* Transmit Underrun need to set TxReset, DMARest, FIFOReset */
+		writew (TxReset | DMAReset | FIFOReset, ioaddr + ASICCtrl + 2);
+		/* Wait for ResetBusy bit clear */
+		for (i = 50; i > 0; i--) {
+			if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+				break;
+			mdelay (1);
+		}
+		/* Reset TFDListPtr */
+		writel (virt_to_bus (&np->tx_ring[frame_id]),
+			dev->base_addr + TFDListPtr0);
+		writel (0, dev->base_addr + TFDListPtr1);
+
+		/* Let TxStartThresh stay default value */
+	}
+	/* Late Collision */
+	if (tx_status & 0x04) {
+		np->stats.tx_fifo_errors++;
+		/* TxReset and clear FIFO */
+		writew (TxReset | FIFOReset, ioaddr + ASICCtrl + 2);
+		/* Wait reset done */
+		for (i = 50; i > 0; i--) {
+			if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+				break;
+			mdelay (1);
+		}
+		/* Let TxStartThresh stay default value */
+	}
+	/* Maximum Collisions */
+#ifdef ETHER_STATS
+	if (tx_status & 0x08)
+		np->stats.collisions16++;
+#else
+	if (tx_status & 0x08)
+		np->stats.collisions++;
+#endif
+
+	/* Restart the Tx. */
+	writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
+}
+
+/* Every interrupts go into here to see if any packet need to process, this
+   ensure Rx rings keep full in a critical cases of Rx rings ran out */
+static int
+receive_packet (struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *) dev->priv;
+	int entry = np->cur_rx % RX_RING_SIZE;
+	int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
+
+	DEBUG_RFD_DUMP (np, 1);
+	/* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */
+	while (np->rx_head_desc->status & RFDDone &&
+	       np->rx_head_desc->status & FrameStart &&
+	       np->rx_head_desc->status & FrameEnd) {
+		struct netdev_desc *desc = np->rx_head_desc;
+		u64 frame_status = le64_to_cpu (desc->status);
+		int pkt_len = le64_to_cpu (desc->status & 0xffff);	/* Chip omits the CRC. */
+
+		if (--cnt < 0)
+			break;
+		DEBUG_PKT_DUMP (np, pkt_len);
+		/* Update rx error statistics, drop packet. */
+		if (frame_status & 0x003f0000) {
+			np->stats.rx_errors++;
+			if (frame_status & 0x00100000)
+				np->stats.rx_length_errors++;
+			if (frame_status & 0x00010000)
+				np->stats.rx_fifo_errors++;
+			if (frame_status & 0x00060000)
+				np->stats.rx_frame_errors++;
+			if (frame_status & 0x00080000)
+				np->stats.rx_crc_errors++;
+		} else {
+			struct sk_buff *skb;
+			/* Small skbuffs for short packets */
+			if (pkt_len > copy_thresh) {
+				skb_put (skb = np->rx_skbuff[entry], pkt_len);
+				np->rx_skbuff[entry] = NULL;
+			} else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve (skb, 2);	/* 16 byte align the IP header */
+				eth_copy_and_sum (skb,
+						  np->rx_skbuff[entry]->tail,
+						  pkt_len, 0);
+				skb_put (skb, pkt_len);
+			}
+			skb->protocol = eth_type_trans (skb, dev);
+#ifdef RX_HW_CHECKSUM
+			/* Checksum done by hw, but csum value unavailable. */
+			if (!(frame_status & (TCPError | UDPError | IPError))) {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			}
+#endif
+			netif_rx (skb);
+			dev->last_rx = jiffies;
+		}
+		entry = (++np->cur_rx) % RX_RING_SIZE;
+		np->rx_head_desc = &np->rx_ring[entry];
+	}
+
+	/* Re-allocate skbuffs to fill the descriptor ring */
+	for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+		struct sk_buff *skb;
+		entry = np->old_rx % RX_RING_SIZE;
+		/* Dropped packets don't need to re-allocate */
+		if (np->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb (np->rx_buf_sz);
+			if (skb == NULL) {
+				np->rx_ring[entry].fraginfo = 0;
+				printk (KERN_ERR
+					"%s: Allocate Rx buffer error!",
+					dev->name);
+				break;
+			}
+			np->rx_skbuff[entry] = skb;
+			skb->dev = dev;
+			skb_reserve (skb, 2);	/* 16 byte align the IP header */
+			np->rx_ring[entry].fraginfo =
+			    virt_to_le64desc (skb->tail);
+		}
+		np->rx_ring[entry].fraginfo |=
+		    cpu_to_le64 (np->rx_buf_sz) << 48;
+		np->rx_ring[entry].status = 0;
+	}
+	/* RxDMAPollNow */
+	writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+		dev->base_addr + DMACtrl);
+
+	DEBUG_RFD_DUMP (np, 2);
+	return 0;
+}
+
+static void
+rio_error (struct net_device *dev, int int_status)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+
+	/* Stop the down counter and recovery the interrupt */
+	if (int_status & IntRequested) {
+
+		writew (0, ioaddr + IntEnable);
+		writel (0, ioaddr + CountDown);
+		/* Enable default interrupts */
+		EnableInt ();
+	}
+
+	/* Link change event */
+	if (int_status & LinkEvent) {
+		if (mii_wait_link (dev, 10) == 0) {
+			printk (KERN_INFO "%s: Link up\n", dev->name);
+			if (np->an_enable) {
+				/* Auto-Negotiation mode */
+				mii_get_media (dev);
+				if (np->full_duplex) {
+					writew (readw (dev->base_addr + MACCtrl)
+						| DuplexSelect,
+						ioaddr + MACCtrl);
+				}
+			}
+		} else {
+			printk (KERN_INFO "%s: Link off\n", dev->name);
+		}
+	}
+
+	/* UpdateStats statistics registers */
+	if (int_status & UpdateStats) {
+		get_stats (dev);
+	}
+
+	/* PCI Error, a catastronphic error related to the bus interface 
+	   occurs, set GlobalReset and HostReset to reset. */
+	if (int_status & HostError) {
+		printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n",
+			dev->name, int_status);
+		writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
+		mdelay (500);
+	}
+}
+
+static struct net_device_stats *
+get_stats (struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+	u16 temp1;
+	u16 temp2;
+	int i;
+	/* All statistics registers need to acknowledge,
+	   else overflow could cause some problem */
+	np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
+	np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
+	np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
+	np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
+	temp1 = readw (ioaddr + FrameLostRxError);
+	np->stats.rx_errors += temp1;
+	np->stats.rx_missed_errors += temp1;
+	np->stats.tx_dropped += readw (ioaddr + FramesAbortXSColls);
+	temp1 = readl (ioaddr + SingleColFrames) +
+	    readl (ioaddr + MultiColFrames) + readl (ioaddr + LateCollisions);
+	temp2 = readw (ioaddr + CarrierSenseErrors);
+	np->stats.tx_carrier_errors += temp2;
+	np->stats.tx_errors += readw (ioaddr + FramesWEXDeferal) +
+	    readl (ioaddr + FramesWDeferredXmt) + temp2;
+
+	/* detailed rx_error */
+	np->stats.rx_length_errors += readw (ioaddr + InRangeLengthErrors) +
+	    readw (ioaddr + FrameTooLongErrors);
+	np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError);
+
+	/* Clear all other statistic register. */
+	readw (ioaddr + MacControlFramesXmtd);
+	readw (ioaddr + BcstFramesXmtdOk);
+	readl (ioaddr + McstFramesXmtdOk);
+	readl (ioaddr + BcstOctetXmtOk);
+	readl (ioaddr + McstOctetXmtOk);
+	readw (ioaddr + MacControlFramesRcvd);
+	readw (ioaddr + BcstFramesRcvOk);
+	readl (ioaddr + McstFramesRcvOk);
+	readl (ioaddr + BcstOctetRcvOk);
+
+	for (i = 0x100; i <= 0x150; i += 4)
+		readl (ioaddr + i);
+	readw (ioaddr + TxJumboFrames);
+	readw (ioaddr + RxJumboFrames);
+	readw (ioaddr + TCPCheckSumErrors);
+	readw (ioaddr + UDPCheckSumErrors);
+	readw (ioaddr + IPCheckSumErrors);
+	return &np->stats;
+}
+
+int
+change_mtu (struct net_device *dev, int new_mtu)
+{
+	int max = (jumbo) ? 9000 : 1536;
+
+	if ((new_mtu < 68) || (new_mtu > max)) {
+		return -EINVAL;
+	}
+
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+#define CRC_POLY 0xedb88320
+static unsigned
+get_crc (unsigned char *p, int len)
+{
+	int bit;
+	unsigned char byte;
+	unsigned crc = 0xffffffff;
+
+	while (--len >= 0) {
+		byte = *p++;
+		for (bit = 0; bit < 8; bit++, byte >>= 1) {
+			crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
+		}
+	}
+	return crc;
+}
+
+static void
+set_multicast (struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	u32 hash_table[2];
+	u16 rx_mode = 0;
+	int i;
+	struct dev_mc_list *mclist;
+	struct netdev_private *np = dev->priv;
+
+	/* Default: receive broadcast and unicast */
+	rx_mode = ReceiveBroadcast | ReceiveUnicast;
+	if (dev->flags & IFF_PROMISC) {
+		/* Receive all frames promiscuously. */
+		rx_mode |= ReceiveAllFrames;
+	} else
+	    if (((dev->flags & IFF_MULTICAST)
+		 && (dev->mc_count > multicast_filter_limit))
+		|| (dev->flags & IFF_ALLMULTI)) {
+		/* Receive broadcast and multicast frames */
+		rx_mode |= ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
+	} else if ((dev->flags & IFF_MULTICAST) & (dev->mc_count > 0)) {
+		/* Receive broadcast frames and multicast frames filtering by Hashtable */
+		rx_mode |=
+		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
+	}
+	if (np->vlan) {
+		/* ReceiveVLANMatch field in ReceiveMode */
+		rx_mode |= ReceiveVLANMatch;
+	}
+	hash_table[0] = 0x00000000;
+	hash_table[1] = 0x00000000;
+
+	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+	     i++, mclist = mclist->next) {
+		set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f,
+			 hash_table);
+	}
+	writel (hash_table[0], ioaddr + HashTable0);
+	writel (hash_table[1], ioaddr + HashTable1);
+	writew (rx_mode, ioaddr + ReceiveMode);
+}
+
+static int
+rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int phy_addr;
+	struct netdev_private *np = dev->priv;
+	struct mii_data *miidata = (struct mii_data *) &rq->ifr_data;
+#ifdef RIO_DEBUG
+	struct ioctl_data *iodata = (struct ioctl_data *) (rq->ifr_data);
+#endif
+	u16 *data = (u16 *) & rq->ifr_data;
+	struct netdev_desc *desc;
+	int i;
+
+	phy_addr = np->phy_addr;
+	switch (cmd) {
+	case SIOCDEVPRIVATE:
+#ifdef RIO_DEBUG
+		if (rio_ioctl_ext (dev, iodata) != 0)
+			return -EOPNOTSUPP;
+		break;
+#else
+		return -EOPNOTSUPP;
+#endif
+	case SIOCDEVPRIVATE + 1:
+		miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
+		break;
+	case SIOCDEVPRIVATE + 2:
+		mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
+		break;
+	case SIOCDEVPRIVATE + 3:
+		np->rx_debug = (data[0] <= 7) ? data[0] : 0;
+		printk ("rx_debug = %d\n", np->rx_debug);
+		break;
+	case SIOCDEVPRIVATE + 4:
+		np->tx_debug = (data[0] <= 7) ? data[0] : 0;
+		printk ("tx_debug = %d\n", np->tx_debug);
+		break;
+	case SIOCDEVPRIVATE + 5:
+		np->tx_full = 1;
+		netif_stop_queue (dev);
+		break;
+	case SIOCDEVPRIVATE + 6:
+		np->tx_full = 0;
+		netif_wake_queue (dev);
+		break;
+	case SIOCDEVPRIVATE + 7:
+		printk ("tx_full=%x cur_tx=%x old_tx=%x cur_rx=%x old_rx=%x\n",
+			(u32) np->tx_full, (u32) np->cur_tx, (u32) np->old_tx,
+			(u32) np->cur_rx, (u32) np->old_rx);
+		break;
+	case SIOCDEVPRIVATE + 8:
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			desc = &np->tx_ring[i];
+			printk
+			    ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+			     (u32) virt_to_bus (desc), (u32) desc->next_desc,
+			     (u32) desc->status, (u32) (desc->fraginfo >> 32),
+			     (u32) desc->fraginfo);
+			printk ("\n");
+		}
+		printk ("\n");
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+#ifdef RIO_DEBUG
+int
+rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata)
+{
+	struct netdev_private *np = dev->priv;
+	int phy_addr = np->phy_addr;
+	u32 hi, lo;
+	int i;
+	BMCR_t bmcr;
+	BMSR_t bmsr;
+
+	if (iodata == NULL)
+		goto invalid_cmd;
+	if (strcmp (iodata->signature, "rio") != 0)
+		goto invalid_cmd;
+
+	switch (iodata->cmd) {
+	case 0:
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			hi = np->tx_ring[i].status >> 32;
+			lo = np->tx_ring[i].status;
+			printk ("TFC=%08x %08x \n", hi, lo);
+
+		}
+		break;
+	case 1:
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			hi = np->rx_ring[i].status >> 32;
+			lo = np->rx_ring[i].status;
+			printk ("RFS=%08x %08x \n", hi, lo);
+		}
+		break;
+	case 2:
+		break;
+	case 3:
+		if (iodata->data != NULL)
+			np->tx_debug = iodata->data[0];
+		break;
+	case 4:
+		/* Soft reset PHY */
+		mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+		bmcr.image = 0;
+		bmcr.bits.an_enable = 1;
+		bmcr.bits.reset = 1;
+		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+		break;
+	case 5:
+		mii_write (dev, phy_addr, MII_BMCR, 0x1940);
+		mdelay (10);
+		mii_write (dev, phy_addr, MII_BMCR, 0x1940);
+		mdelay (100);	/* wait a certain time */
+		break;
+	case 6:
+		/* 5) Set media and Power Up */
+		bmcr.image = 0;
+		bmcr.bits.power_down = 1;
+		if (np->an_enable) {
+			bmcr.bits.an_enable = 1;
+		} else {
+			if (np->speed == 100) {
+				bmcr.bits.speed100 = 1;
+				bmcr.bits.speed1000 = 0;
+				printk ("Manual 100 Mbps, ");
+			} else if (np->speed == 10) {
+				bmcr.bits.speed100 = 0;
+				bmcr.bits.speed1000 = 0;
+				printk ("Manual 10 Mbps, ");
+			}
+			if (np->full_duplex) {
+				bmcr.bits.duplex_mode = 1;
+				printk ("Full duplex. \n");
+			} else {
+				bmcr.bits.duplex_mode = 0;
+				printk ("Half duplex.\n");
+			}
+		}
+		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+		break;
+	case 7:
+		bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+		bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+		printk ("BMCR=%x BMSR=%x LinkUp=%d\n",
+			bmcr.image, bmsr.image, bmsr.bits.link_status);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+
+invalid_cmd:
+	return -1;
+}
+#endif
+#define EEP_READ 0x0200
+#define EEP_BUSY 0x8000
+/* Read the EEPROM word */
+int
+read_eeprom (long ioaddr, int eep_addr)
+{
+	int i = 1000;
+	writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+	while (i-- > 0) {
+		if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+			return readw (ioaddr + EepromData);
+		}
+	}
+	return 0;
+}
+
+enum phy_ctrl_bits {
+	MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04,
+	MII_DUPLEX = 0x08,
+};
+
+#define mii_delay() readb(ioaddr)
+static void
+mii_sendbit (struct net_device *dev, u32 data)
+{
+	int ioaddr = dev->base_addr + PhyCtrl;
+	data = (data) ? MII_DATA1 : 0;
+	data |= MII_WRITE;
+	data |= (readb (ioaddr) & 0xf8) | MII_WRITE;
+	writeb (data, ioaddr);
+	mii_delay ();
+	writeb (data | MII_CLK, ioaddr);
+	mii_delay ();
+}
+
+static int
+mii_getbit (struct net_device *dev)
+{
+	int ioaddr = dev->base_addr + PhyCtrl;
+	u8 data;
+
+	data = (readb (ioaddr) & 0xf8) | MII_READ;
+	writeb (data, ioaddr);
+	mii_delay ();
+	writeb (data | MII_CLK, ioaddr);
+	mii_delay ();
+	return ((readb (ioaddr) >> 1) & 1);
+}
+
+static void
+mii_send_bits (struct net_device *dev, u32 data, int len)
+{
+	int i;
+	for (i = len - 1; i >= 0; i--) {
+		mii_sendbit (dev, data & (1 << i));
+	}
+}
+
+static int
+mii_read (struct net_device *dev, int phy_addr, int reg_num)
+{
+	u32 cmd;
+	int i;
+	u32 retval = 0;
+
+	/* Preamble */
+	mii_send_bits (dev, 0xffffffff, 32);
+	/* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+	/* ST,OP = 0110'b for read operation */
+	cmd = (0x06 << 10 | phy_addr << 5 | reg_num);
+	mii_send_bits (dev, cmd, 14);
+	/* Turnaround */
+	if (mii_getbit (dev))
+		goto err_out;
+	/* Read data */
+	for (i = 0; i < 16; i++) {
+		retval |= mii_getbit (dev);
+		retval <<= 1;
+	}
+	/* End cycle */
+	mii_getbit (dev);
+	return (retval >> 1) & 0xffff;
+
+err_out:
+	return 0;
+}
+static int
+mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
+{
+	u32 cmd;
+
+	/* Preamble */
+	mii_send_bits (dev, 0xffffffff, 32);
+	/* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+	/* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x0502 for write */
+	cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data;
+	mii_send_bits (dev, cmd, 32);
+	/* End cycle */
+	mii_getbit (dev);
+	return 0;
+}
+static int
+mii_wait_link (struct net_device *dev, int wait)
+{
+	BMSR_t bmsr;
+	int phy_addr;
+	struct netdev_private *np;
+
+	np = dev->priv;
+	phy_addr = np->phy_addr;
+
+	do {
+		bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+		if (bmsr.bits.link_status)
+			return 0;
+		mdelay (1);
+	} while (--wait > 0);
+	return -1;
+}
+static int
+mii_get_media (struct net_device *dev)
+{
+	ANAR_t negotiate;
+	BMSR_t bmsr;
+	BMCR_t bmcr;
+	MSCR_t mscr;
+	MSSR_t mssr;
+	int phy_addr;
+	struct netdev_private *np;
+
+	np = dev->priv;
+	phy_addr = np->phy_addr;
+
+	bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+	if (np->an_enable) {
+		if (!bmsr.bits.an_complete) {
+			/* Auto-Negotiation not completed */
+			return -1;
+		}
+		negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
+		    mii_read (dev, phy_addr, MII_ANLPAR);
+		mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+		mssr.image = mii_read (dev, phy_addr, MII_MSSR);
+		if (mscr.bits.media_1000BT_FD & mssr.bits.lp_1000BT_FD) {
+			np->speed = 1000;
+			np->full_duplex = 1;
+			printk (KERN_INFO "Auto 1000BaseT, Full duplex.\n");
+		} else if (mscr.bits.media_1000BT_HD & mssr.bits.lp_1000BT_HD) {
+			np->speed = 1000;
+			np->full_duplex = 0;
+			printk (KERN_INFO "Auto 1000BaseT, Half duplex.\n");
+		} else if (negotiate.bits.media_100BX_FD) {
+			np->speed = 100;
+			np->full_duplex = 1;
+			printk (KERN_INFO "Auto 100BaseT, Full duplex.\n");
+		} else if (negotiate.bits.media_100BX_HD) {
+			np->speed = 100;
+			np->full_duplex = 0;
+			printk (KERN_INFO "Auto 100BaseT, Half duplex.\n");
+		} else if (negotiate.bits.media_10BT_FD) {
+			np->speed = 10;
+			np->full_duplex = 1;
+			printk (KERN_INFO "Auto 10BaseT, Full duplex.\n");
+		} else if (negotiate.bits.media_10BT_HD) {
+			np->speed = 10;
+			np->full_duplex = 0;
+			printk (KERN_INFO "Auto 10BaseT, Half duplex.\n");
+		}
+	} else {
+		bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+		if (bmcr.bits.speed100 == 1 && bmcr.bits.speed1000 == 0) {
+			printk (KERN_INFO "Operating at 100 Mbps, ");
+		} else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 0) {
+			printk (KERN_INFO "Operating at 10 Mbps, ");
+		} else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 1) {
+			printk (KERN_INFO "Operating at 1000 Mbps, ");
+		}
+		if (bmcr.bits.duplex_mode) {
+			printk ("Full duplex.\n");
+		} else {
+			printk ("Half duplex.\n");
+		}
+	}
+	return 0;
+}
+
+static int
+mii_set_media (struct net_device *dev)
+{
+	PHY_SCR_t pscr;
+	BMCR_t bmcr;
+	BMSR_t bmsr;
+	ANAR_t anar;
+	int phy_addr;
+	struct netdev_private *np;
+	np = dev->priv;
+	phy_addr = np->phy_addr;
+
+	/* Does user set speed? */
+	if (np->an_enable) {
+		/* Reset to enable Auto-Negotiation */
+		bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+		anar.image = mii_read (dev, phy_addr, MII_ANAR);
+		anar.bits.media_100BX_FD = bmsr.bits.media_100BX_FD;
+		anar.bits.media_100BX_HD = bmsr.bits.media_100BX_HD;
+		anar.bits.media_100BT4 = bmsr.bits.media_100BT4;
+		anar.bits.media_10BT_FD = bmsr.bits.media_10BT_FD;
+		anar.bits.media_10BT_HD = bmsr.bits.media_10BT_HD;
+		mii_write (dev, phy_addr, MII_ANAR, anar.image);
+
+		/* Enable Auto crossover */
+		pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+		pscr.bits.mdi_crossover_mode = 3;	/* 11'b */
+		mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+		/* Soft reset PHY */
+		mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+		bmcr.image = 0;
+		bmcr.bits.an_enable = 1;
+		bmcr.bits.reset = 1;
+		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+		/* Wait for Link up, link up need a certain time */
+		if (mii_wait_link (dev, 3200) != 0) {
+			printk (KERN_INFO "Link time out\n");
+		}
+		mdelay (1);
+		mii_get_media (dev);
+	} else {
+		/* Force speed setting */
+		/* 1) Disable Auto crossover */
+		pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+		pscr.bits.mdi_crossover_mode = 0;
+		mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+
+		/* 2) PHY Reset */
+		bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+		bmcr.bits.reset = 1;
+		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+
+		/* 3) Power Down */
+		bmcr.image = 0x1940;	/* must be 0x1940 */
+		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+		mdelay (10);	/* wait a certain time */
+
+		/* 4) Advertise nothing */
+		mii_write (dev, phy_addr, MII_ANAR, 0);
+
+		/* 5) Set media and Power Up */
+		bmcr.image = 0;
+		bmcr.bits.power_down = 1;
+		if (np->speed == 100) {
+			bmcr.bits.speed100 = 1;
+			bmcr.bits.speed1000 = 0;
+			printk (KERN_INFO "Manual 100 Mbps, ");
+		} else if (np->speed == 10) {
+			bmcr.bits.speed100 = 0;
+			bmcr.bits.speed1000 = 0;
+			printk (KERN_INFO "Manual 10 Mbps, ");
+		}
+		if (np->full_duplex) {
+			bmcr.bits.duplex_mode = 1;
+			printk ("Full duplex. \n");
+		} else {
+			bmcr.bits.duplex_mode = 0;
+			printk ("Half duplex.\n");
+		}
+#if 0
+		/* Set 1000BaseT Master/Slave setting */
+		mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+		mscr.bits.cfg_enable = 1;
+		mscr.bits.cfg_value = 0;
+#endif
+		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+
+		/* Wait for Link up, link up need a certain time */
+		if (mii_wait_link (dev, 3200) != 0) {
+			printk (KERN_INFO "Link time out\n");
+		}
+		mii_get_media (dev);
+	}
+	return 0;
+}
+
+static int
+rio_close (struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	netif_stop_queue (dev);
+
+	/* Disable interrupts */
+	writew (0, ioaddr + IntEnable);
+
+	/* Stop Tx and Rx logics */
+	writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
+	synchronize_irq ();
+	free_irq (dev->irq, dev);
+
+	/* Free all the skbuffs in the queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].status = 0;
+		np->rx_ring[i].fraginfo = 0;
+		if (np->rx_skbuff[i]) {
+			dev_kfree_skb (np->rx_skbuff[i]);
+		}
+		np->rx_skbuff[i] = 0;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (np->tx_skbuff[i])
+			dev_kfree_skb (np->tx_skbuff[i]);
+		np->tx_skbuff[i] = 0;
+	}
+	return 0;
+}
+
+static void __devexit
+rio_remove1 (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	if (dev) {
+		unregister_netdev (dev);
+#ifndef USE_IO_OPS
+		iounmap ((char *) (dev->base_addr));
+#endif
+		kfree (dev);
+		pci_release_regions (pdev);
+		pci_disable_device (pdev);
+	}
+	pci_set_drvdata (pdev, NULL);
+}
+
+static struct pci_driver rio_driver = {
+	name:		"dl2k",
+	id_table:	rio_pci_tbl,
+	probe:		rio_probe1,
+	remove:		rio_remove1,
+};
+
+static int __init
+rio_init (void)
+{
+#ifdef MODULE
+	printk ("%s", version);
+#endif
+
+	return pci_module_init (&rio_driver);
+}
+
+static void __exit
+rio_exit (void)
+{
+	pci_unregister_driver (&rio_driver);
+}
+
+module_init (rio_init);
+module_exit (rio_exit);
+
+/*
+ 
+Compile command: 
+ 
+gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c
+
+*/
diff -u --recursive --new-file v2.4.6/linux/drivers/net/dl2k.h linux/drivers/net/dl2k.h
--- v2.4.6/linux/drivers/net/dl2k.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/dl2k.h	Fri Jul  6 16:48:50 2001
@@ -0,0 +1,729 @@
+/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*  
+    Copyright (c) 2001 by D-Link Corporation
+    Written by Edward Peng.<edward_peng@dlink.com.tw>
+    Created 03-May-2001, base on Linux' sundance.c.
+
+    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.
+*/
+
+#ifndef __DL2K_H__
+#define __DL2K_H__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#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>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#define TX_RING_SIZE	16
+#define TX_QUEUE_LEN	10	/* Limit ring entries actually used.  */
+#define RX_RING_SIZE	16
+
+#define virt_to_le64desc(addr)  cpu_to_le64(virt_to_bus(addr))
+#define le64desc_to_virt(addr)  bus_to_virt(le64_to_cpu(addr))
+/* This driver was written to use PCI memory space, however x86-oriented
+   hardware often uses I/O space accesses. */
+#ifdef USE_IO_OPS
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb inb
+#define readw inw
+#define readl inl
+#define writeb outb
+#define writew outw
+#define writel outl
+#endif
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum dl2x_offsets {
+	/* I/O register offsets */
+	DMACtrl = 0x00,
+	RxDMAStatus = 0x08,
+	TFDListPtr0 = 0x10,
+	TFDListPtr1 = 0x14,
+	TxDMABurstThresh = 0x18,
+	TxDMAUrgentThresh = 0x19,
+	TxDMAPollPeriod = 0x1a,
+	RFDListPtr0 = 0x1c,
+	RFDListPtr1 = 0x20,
+	RxDMABurstThresh = 0x24,
+	RxDMAUrgentThresh = 0x25,
+	RxDMAPollPeriod = 0x26,
+	RxDMAIntCtrl = 0x28,
+	DebugCtrl = 0x2c,
+	ASICCtrl = 0x30,
+	FifoCtrl = 0x38,
+	RxEarlyThresh = 0x3a,
+	FlowOffThresh = 0x3c,
+	FlowOnThresh = 0x3e,
+	TxStartThresh = 0x44,
+	EepromData = 0x48,
+	EepromCtrl = 0x4a,
+	ExpromAddr = 0x4c,
+	Exprodata = 0x50,
+	WakeEvent0x51,
+	CountDown = 0x54,
+	IntStatusAck = 0x5a,
+	IntEnable = 0x5c,
+	IntStatus = 0x5e,
+	TxStatus = 0x60,
+	MACCtrl = 0x6c,
+	VLANTag = 0x70,
+	PhyCtrl = 0x76,
+	StationAddr0 = 0x78,
+	StationAddr1 = 0x7a,
+	StationAddr2 = 0x7c,
+	VLANId = 0x80,
+	MaxFrameSize = 0x86,
+	ReceiveMode = 0x88,
+	HashTable0 = 0x8c,
+	HashTable1 = 0x90,
+	RmonStatMask = 0x98,
+	StatMask = 0x9c,
+	RxJumboFrames = 0xbc,
+	TCPCheckSumErrors = 0xc0,
+	IPCheckSumErrors = 0xc2,
+	UDPCheckSumErrors = 0xc4,
+	TxJumboFrames = 0xf4,
+	/* Ethernet MIB statistic register offsets */
+	OctetRcvOk = 0xa8,
+	McstOctetRcvOk = 0xac,
+	BcstOctetRcvOk = 0xb0,
+	FramesRcvOk = 0xb4,
+	McstFramesRcvOk = 0xb8,
+	BcstFramesRcvOk = 0xbe,
+	MacControlFramesRcvd = 0xc6,
+	FrameTooLongErrors = 0xc8,
+	InRangeLengthErrors = 0xca,
+	FrameCheckSeqError = 0xcc,
+	FrameLostRxError = 0xce,
+	OctetXmtOk = 0xd0,
+	McstOctetXmtOk = 0xd4,
+	BcstOctetXmtOk = 0xd8,
+	FramesXmtOk = 0xdc,
+	McstFramesXmtdOk = 0xe0,
+	FramesWDeferredXmt = 0xe4,
+	LateCollisions = 0xe8,
+	MultiColFrames = 0xec,
+	SingleColFrames = 0xf0,
+	BcstFramesXmtdOk = 0xf6,
+	CarrierSenseErrors = 0xf8,
+	MacControlFramesXmtd = 0xfa,
+	FramesAbortXSColls = 0xfc,
+	FramesWEXDeferal = 0xfe,
+	/* RMON statistic register offsets */
+	EtherStatsCollisions = 0x100,
+	EtherStatsOctetsTransmit = 0x104,
+	EtherStatsPktsTransmit = 0x108,
+	EtherStatsPkts64OctetTransmit = 0x10c,
+	EtherStats65to127OctetsTransmit = 0x110,
+	EtherStatsPkts128to255OctetsTransmit = 0x114,
+	EtherStatsPkts256to511OctetsTransmit = 0x118,
+	EtherStatsPkts512to1023OctetsTransmit = 0x11c,
+	EtherStatsPkts1024to1518OctetsTransmit = 0x120,
+	EtherStatsCRCAlignErrors = 0x124,
+	EtherStatsUndersizePkts = 0x128,
+	EtherStatsFragments = 0x12c,
+	EtherStatsJabbers = 0x130,
+	EtherStatsOctets = 0x134,
+	EtherStatsPkts = 0x138,
+	EtherStats64Octets = 0x13c,
+	EtherStatsPkts65to127Octets = 0x140,
+	EtherStatsPkts128to255Octets = 0x144,
+	EtherStatsPkts256to511Octets = 0x148,
+	EtherStatsPkts512to1023Octets = 0x14c,
+	EtherStatsPkts1024to1518Octets = 0x150,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum IntStatus_bits {
+	InterruptStatus = 0x0001,
+	HostError = 0x0002,
+	MACCtrlFrame = 0x0008,
+	TxComplete = 0x0004,
+	RxComplete = 0x0010,
+	RxEarly = 0x0020,
+	IntRequested = 0x0040,
+	UpdateStats = 0x0080,
+	LinkEvent = 0x0100,
+	TxDMAComplete = 0x0200,
+	RxDMAComplete = 0x0400,
+	RFDListEnd = 0x0800,
+	RxDMAPriority = 0x1000,
+};
+
+/* Bits in the ReceiveMode register. */
+enum ReceiveMode_bits {
+	ReceiveIPMulticast = 0x0020,
+	ReceiveMulticastHash = 0x0010,
+	ReceiveAllFrames = 0x0008,
+	ReceiveBroadcast = 0x0004,
+	ReceiveMulticast = 0x0002,
+	ReceiveUnicast = 0x0001,
+	ReceiveVLANMatch = 0x0100,
+	ReceiveVLANHash = 0x0200,
+};
+/* Bits in MACCtrl. */
+enum MACCtrl_bits {
+	DuplexSelect = 0x20,
+	RcvFCS = 0x200,
+	AutoVLANtagging = 0x1000,
+	AutoVLANuntagging = 0x2000,
+	StatsEnable = 0x00200000,
+	StatsDisable = 0x00400000,
+	StatsEnabled = 0x00800000,
+	TxEnable = 0x01000000,
+	TxDisable = 0x02000000,
+	TxEnabled = 0x04000000,
+	RxEnable = 0x08000000,
+	RxDisable = 0x10000000,
+	RxEnabled = 0x20000000,
+};
+enum ASICCtrl_HiWord_bits {
+	GlobalReset = 0x0001,
+	RxReset = 0x0002,
+	TxReset = 0x0004,
+	DMAReset = 0x0008,
+	FIFOReset = 0x0010,
+	NetworkReset = 0x0020,
+	HostReset = 0x0040,
+	ResetBusy = 0x0400,
+};
+
+/* Transmit Frame Control bits */
+enum TFC_bits {
+	DwordAlign = 0x00000000,
+	WordAlignDisable = 0x00030000,
+	WordAlign = 0x00020000,
+	TCPChecksumEnable = 0x00040000,
+	UDPChecksumEnable = 0x00080000,
+	IPChecksumEnable = 0x00100000,
+	FCSAppendDisable = 0x00200000,
+	TxIndicate = 0x00400000,
+	TxDMAIndicate = 0x00800000,
+	FragCountShift = 24,
+	VLANTagInsert = 0x0000000010000000,
+	TFDDone = 0x80000000,
+	VIDShift = 32,
+	CFI = 0x0000100000000000,
+	UsePriorityShift = 48,
+};
+
+/* Receive Frames Status bits */
+enum RFS_bits {
+	RxFIFOOverrun = 0x00010000,
+	RxRuntFrame = 0x00020000,
+	RxAlignmentError = 0x00040000,
+	RxFCSError = 0x00080000,
+	RxOverSizedFrame = 0x00100000,
+	RxLengthError = 0x00200000,
+	VLANDetected = 0x00400000,
+	TCPDetected = 0x00800000,
+	TCPError = 0x01000000,
+	UDPDetected = 0x02000000,
+	UDPError = 0x04000000,
+	IPDetected = 0x08000000,
+	IPError = 0x10000000,
+	FrameStart = 0x20000000,
+	FrameEnd = 0x40000000,
+	RFDDone = 0x80000000,
+	TCIShift = 32,
+};
+
+#define MII_RESET_TIME_OUT		10000
+/* MII register */
+enum _mii_reg {
+	MII_BMCR = 0,
+	MII_BMSR = 1,
+	MII_PHY_ID1 = 2,
+	MII_PHY_ID2 = 3,
+	MII_ANAR = 4,
+	MII_ANLPAR = 5,
+	MII_ANER = 6,
+	MII_ANNPT = 7,
+	MII_ANLPRNP = 8,
+	MII_MSCR = 9,
+	MII_MSSR = 10,
+	MII_ESR = 15,
+	MII_PHY_SCR = 16,
+};
+
+/* Basic Mode Control Register */
+typedef union t_MII_BMCR {
+	u16 image;
+	struct {
+		u16 _bit_5_0:6;	// bit 5:0
+		u16 speed1000:1;	// bit 6
+		u16 col_test_enable:1;	// bit 7
+		u16 duplex_mode:1;	// bit 8
+		u16 restart_an:1;	// bit 9
+		u16 isolate:1;	// bit 10
+		u16 power_down:1;	// bit 11
+		u16 an_enable:1;	// bit 12
+		u16 speed100:1;	// bit 13
+		u16 loopback:1;	// bit 14
+		u16 reset:1;	// bit 15
+	} bits;
+} BMCR_t, *PBMCR_t;
+
+enum _mii_bmcr {
+	MII_BMCR_RESET = 0x8000,
+	MII_BMCR_LOOP_BACK = 0x4000,
+	MII_BMCR_SPEED_LSB = 0x2000,
+	MII_BMCR_AN_ENABLE = 0x1000,
+	MII_BMCR_POWER_DOWN = 0x0800,
+	MII_BMCR_ISOLATE = 0x0400,
+	MII_BMCR_RESTART_AN = 0x0200,
+	MII_BMCR_DUPLEX_MODE = 0x0100,
+	MII_BMCR_COL_TEST = 0x0080,
+	MII_BMCR_SPEED_MSB = 0x0040,
+	MII_BMCR_SPEED_RESERVED = 0x003f,
+	MII_BMCR_SPEED_10 = 0,
+	MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB,
+	MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB,
+};
+
+/* Basic Mode Status Register */
+typedef union t_MII_BMSR {
+	u16 image;
+	struct {
+		u16 ext_capability:1;	// bit 0
+		u16 japper_detect:1;	// bit 1
+		u16 link_status:1;	// bit 2
+		u16 an_ability:1;	// bit 3
+		u16 remote_fault:1;	// bit 4
+		u16 an_complete:1;	// bit 5
+		u16 preamble_supp:1;	// bit 6
+		u16 _bit_7:1;	// bit 7
+		u16 ext_status:1;	// bit 8
+		u16 media_100BT2_HD:1;	// bit 9
+		u16 media_100BT2_FD:1;	// bit 10
+		u16 media_10BT_HD:1;	// bit 11
+		u16 media_10BT_FD:1;	// bit 12
+		u16 media_100BX_HD:1;	// bit 13
+		u16 media_100BX_FD:1;	// bit 14
+		u16 media_100BT4:1;	// bit 15
+	} bits;
+} BMSR_t, *PBMSR_t;
+
+enum _mii_bmsr {
+	MII_BMSR_100BT4 = 0x8000,
+	MII_BMSR_100BX_FD = 0x4000,
+	MII_BMSR_100BX_HD = 0x2000,
+	MII_BMSR_10BT_FD = 0x1000,
+	MII_BMSR_10BT_HD = 0x0800,
+	MII_BMSR_100BT2_FD = 0x0400,
+	MII_BMSR_100BT2_HD = 0x0200,
+	MII_BMSR_EXT_STATUS = 0x0100,
+	MII_BMSR_PREAMBLE_SUPP = 0x0040,
+	MII_BMSR_AN_COMPLETE = 0x0020,
+	MII_BMSR_REMOTE_FAULT = 0x0010,
+	MII_BMSR_AN_ABILITY = 0x0008,
+	MII_BMSR_LINK_STATUS = 0x0004,
+	MII_BMSR_JABBER_DETECT = 0x0002,
+	MII_BMSR_EXT_CAP = 0x0001,
+};
+
+/* ANAR */
+typedef union t_MII_ANAR {
+	u16 image;
+	struct {
+		u16 selector:5;	// bit 4:0
+		u16 media_10BT_HD:1;	// bit 5
+		u16 media_10BT_FD:1;	// bit 6
+		u16 media_100BX_HD:1;	// bit 7
+		u16 media_100BX_FD:1;	// bit 8
+		u16 media_100BT4:1;	// bit 9
+		u16 pause:1;	// bit 10
+		u16 asymmetric:1;	// bit 11
+		u16 _bit12:1;	// bit 12
+		u16 remote_fault:1;	// bit 13
+		u16 _bit14:1;	// bit 14
+		u16 next_page:1;	// bit 15
+	} bits;
+} ANAR_t, *PANAR_t;
+
+enum _mii_anar {
+	MII_ANAR_NEXT_PAGE = 0x8000,
+	MII_ANAR_REMOTE_FAULT = 0x4000,
+	MII_ANAR_ASYMMETRIC = 0x0800,
+	MII_ANAR_PAUSE = 0x0400,
+	MII_ANAR_100BT4 = 0x0200,
+	MII_ANAR_100BX_FD = 0x0100,
+	MII_ANAR_100BX_HD = 0x0080,
+	MII_ANAR_10BT_FD = 0x0020,
+	MII_ANAR_10BT_HD = 0x0010,
+	MII_ANAR_SELECTOR = 0x001f,
+	MII_IEEE8023_CSMACD = 0x0001,
+};
+
+/* ANLPAR */
+typedef union t_MII_ANLPAR {
+	u16 image;
+	struct {
+		u16 selector:5;	// bit 4:0
+		u16 media_10BT_HD:1;	// bit 5
+		u16 media_10BT_FD:1;	// bit 6
+		u16 media_100BX_HD:1;	// bit 7
+		u16 media_100BX_FD:1;	// bit 8
+		u16 media_100BT4:1;	// bit 9
+		u16 pause:1;	// bit 10
+		u16 asymmetric:1;	// bit 11
+		u16 _bit12:1;	// bit 12
+		u16 remote_fault:1;	// bit 13
+		u16 _bit14:1;	// bit 14
+		u16 next_page:1;	// bit 15
+	} bits;
+} ANLPAR_t, *PANLPAR_t;
+
+enum _mii_anlpar {
+	MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
+	MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
+	MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC,
+	MII_ANLPAR_PAUSE = MII_ANAR_PAUSE,
+	MII_ANLPAR_100BT4 = MII_ANAR_100BT4,
+	MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD,
+	MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD,
+	MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD,
+	MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD,
+	MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR,
+};
+
+/* Auto-Negotiation Expansion Register */
+typedef union t_MII_ANER {
+	u16 image;
+	struct {
+		u16 lp_negotiable:1;	// bit 0
+		u16 page_received:1;	// bit 1
+		u16 nextpagable:1;	// bit 2
+		u16 lp_nextpagable:1;	// bit 3
+		u16 pdetect_fault:1;	// bit 4
+		u16 _bit15_5:11;	// bit 15:5
+	} bits;
+} ANER_t, *PANER_t;
+
+enum _mii_aner {
+	MII_ANER_PAR_DETECT_FAULT = 0x0010,
+	MII_ANER_LP_NEXTPAGABLE = 0x0008,
+	MII_ANER_NETXTPAGABLE = 0x0004,
+	MII_ANER_PAGE_RECEIVED = 0x0002,
+	MII_ANER_LP_NEGOTIABLE = 0x0001,
+};
+
+/* MASTER-SLAVE Control Register */
+typedef union t_MII_MSCR {
+	u16 image;
+	struct {
+		u16 _bit_7_0:8;	// bit 7:0
+		u16 media_1000BT_HD:1;	// bit 8
+		u16 media_1000BT_FD:1;	// bit 9
+		u16 port_type:1;	// bit 10
+		u16 cfg_value:1;	// bit 11
+		u16 cfg_enable:1;	// bit 12
+		u16 test_mode:3;	// bit 15:13
+	} bits;
+} MSCR_t, *PMSCR_t;
+
+enum _mii_mscr {
+	MII_MSCR_TEST_MODE = 0xe000,
+	MII_MSCR_CFG_ENABLE = 0x1000,
+	MII_MSCR_CFG_VALUE = 0x0800,
+	MII_MSCR_PORT_VALUE = 0x0400,
+	MII_MSCR_1000BT_FD = 0x0200,
+	MII_MSCR_1000BT_HD = 0X0100,
+};
+
+/* MASTER-SLAVE Status Register */
+typedef union t_MII_MSSR {
+	u16 image;
+	struct {
+		u16 idle_err_count:8;	// bit 7:0
+		u16 _bit_9_8:2;	// bit 9:8
+		u16 lp_1000BT_HD:1;	// bit 10
+		u16 lp_1000BT_FD:1;	// bit 11
+		u16 remote_rcv_status:1;	// bit 12
+		u16 local_rcv_status:1;	// bit 13
+		u16 cfg_resolution:1;	// bit 14
+		u16 cfg_fault:1;	// bit 15
+	} bits;
+} MSSR_t, *PMSSR_t;
+
+enum _mii_mssr {
+	MII_MSSR_CFG_FAULT = 0x8000,
+	MII_MSSR_CFG_RES = 0x4000,
+	MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
+	MII_MSSR_REMOTE_RCVR = 0x1000,
+	MII_MSSR_LP_1000BT_HD = 0x0800,
+	MII_MSSR_LP_1000BT_FD = 0x0400,
+	MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
+};
+
+/* IEEE Extened Status Register */
+typedef union t_MII_ESR {
+	u16 image;
+	struct {
+		u16 _bit_11_0:12;	// bit 11:0
+		u16 media_1000BT_HD:2;	// bit 12
+		u16 media_1000BT_FD:1;	// bit 13
+		u16 media_1000BX_HD:1;	// bit 14
+		u16 media_1000BX_FD:1;	// bit 15
+	} bits;
+} ESR_t, *PESR_t;
+
+enum _mii_esr {
+	MII_ESR_1000BX_FD = 0x8000,
+	MII_ESR_1000BX_HD = 0x4000,
+	MII_ESR_1000BT_FD = 0x2000,
+	MII_ESR_1000BT_HD = 0x1000,
+};
+/* PHY Specific Control Register */
+typedef union t_MII_PHY_SCR {
+	u16 image;
+	struct {
+		u16 disable_jabber:1;	// bit 0
+		u16 polarity_reversal:1;	// bit 1
+		u16 SEQ_test:1;	// bit 2
+		u16 _bit_3:1;	// bit 3
+		u16 disable_CLK125:1;	// bit 4
+		u16 mdi_crossover_mode:2;	// bit 6:5
+		u16 enable_ext_dist:1;	// bit 7
+		u16 _bit_8_9:2;	// bit 9:8
+		u16 force_link:1;	// bit 10
+		u16 assert_CRS:1;	// bit 11
+		u16 rcv_fifo_depth:2;	// bit 13:12
+		u16 xmit_fifo_depth:2;	// bit 15:14
+	} bits;
+} PHY_SCR_t, *PPHY_SCR_t;
+
+typedef enum t_MII_ADMIN_STATUS {
+	adm_reset,
+	adm_operational,
+	adm_loopback,
+	adm_power_down,
+	adm_isolate
+} MII_ADMIN_t, *PMII_ADMIN_t;
+
+typedef struct t_SROM {
+	u16 config_param;	/* 0x00 */
+	u16 asic_ctrl;		/* 0x02 */
+	u16 sub_vendor_id;	/* 0x04 */
+	u16 sub_system_id;	/* 0x06 */
+	u16 reserved1[12];	/* 0x08-0x1f */
+	u8 mac_addr[6];		/* 0x20-0x25 */
+	u8 reserved2[10];	/* 0x26-0x2f */
+	u8 sib[204];		/* 0x30-0xfb */
+	u32 crc;		/* 0xfc-0xff */
+} SROM_t, *PSROM_t;
+
+/* Ioctl custom data */
+struct ioctl_data {
+	char signature[10];
+	int cmd;
+	int len;
+	char *data;
+};
+
+struct mii_data {
+	__u16 reserved;
+	__u16 reg_num;
+	__u16 in_value;
+	__u16 out_value;
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct netdev_desc {
+	u64 next_desc;
+	u64 status;
+	u64 fraginfo;
+};
+
+#define PRIV_ALIGN	15	/* Required alignment mask */
+/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
+   within the structure. */
+struct netdev_private {
+	/* Descriptor rings first for alignment. */
+	struct netdev_desc rx_ring[RX_RING_SIZE];
+	struct netdev_desc tx_ring[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff *rx_skbuff[RX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for later free(). */
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	struct net_device_stats stats;
+	spinlock_t lock;
+	struct netdev_desc *rx_head_desc;
+	unsigned int rx_buf_sz;	/* Based on MTU+slack. */
+	unsigned int tx_full:1;	/* The Tx queue is full. */
+	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
+	unsigned int speed;	/* Operating speed */
+	unsigned int vlan;	/* VLAN Id */
+	unsigned int an_enable;	/* Auto-Negotiated Enable */
+	unsigned int chip_id;	/* PCI table chip id */
+	unsigned int jumbo;
+	struct netdev_desc *last_tx;	/* Last Tx descriptor used. */
+	u64 cur_rx, old_rx;	/* Producer/consumer ring indices */
+	u64 cur_tx, old_tx;
+	int wake_polarity;
+	char name[256];		/* net device description */
+	u8 duplex_polarity;
+	u16 mcast_filter[4];
+	u16 advertising;	/* NWay media advertisement */
+	u16 negotiate;		/* Negotiated media */
+	int phy_addr;		/* PHY addresses. */
+	int tx_debug;
+	int rx_debug;
+};
+
+/* The station address location in the EEPROM. */
+#ifdef USE_IO_OPS
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
+#else
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+#endif
+/* The struct pci_device_id consist of:
+        vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
+        subvendor, subdevice    Subsystem vendor and device ID to match (or PCI_ANY_ID)
+        class                   Device class to match. The class_mask tells which bits
+        class_mask              of the class are honored during the comparison.
+        driver_data             Data private to the driver.
+*/
+static struct pci_device_id rio_pci_tbl[] __devinitdata = {
+	{0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
+#define TX_TIMEOUT  (4*HZ)
+#define PACKET_SIZE		1536
+#define RIO_IO_SIZE             340
+#ifdef RIO_DEBUG
+#define DEBUG_TFD_DUMP(x) debug_tfd_dump(x)
+#define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag)
+#define DEBUG_PKT_DUMP(x,len) debug_pkt_dump(x,len)
+#define DEBUG_PRINT printk
+
+static inline void
+debug_tfd_dump (struct netdev_private *np)
+{
+	int i;
+	struct netdev_desc *desc;
+
+	if (np->tx_debug == 6) {
+		printk ("TFDone Dump: ");
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			desc = &np->tx_ring[i];
+			if ((desc->fraginfo & 0xffffffffff) == 0)
+				printk ("X");
+			else
+				printk ("%d", (desc->status & TFDDone) ? 1 : 0);
+		}
+		printk ("\n");
+	}
+	if (np->tx_debug == 5) {
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			desc = &np->tx_ring[i];
+			printk
+			    ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+			     (u32) virt_to_bus (desc), (u32) desc->next_desc,
+			     (u32) desc->status, (u32) (desc->fraginfo >> 32),
+			     (u32) desc->fraginfo);
+			printk ("\n");
+		}
+		printk ("\n");
+	}
+}
+static inline void
+debug_rfd_dump (struct netdev_private *np, int flag)
+{
+	int i;
+	struct netdev_desc *desc;
+	int entry = np->cur_rx % RX_RING_SIZE;
+
+	if (np->rx_debug == 5) {
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			desc = &np->rx_ring[i];
+			printk
+			    ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+			     (u32) virt_to_bus (desc), (u32) desc->next_desc,
+			     (u32) desc->status, (u32) (desc->fraginfo >> 32),
+			     (u32) desc->fraginfo);
+			printk ("\n");
+		}
+		printk ("\n");
+	}
+
+	if (np->rx_debug == 6) {
+		if (flag == 1)
+			printk ("RFDone Dump: ");
+		else if (flag == 2)
+			printk ("Re-Filling:  ");
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			desc = &np->rx_ring[i];
+			printk ("%d", (desc->status & RFDDone) ? 1 : 0);
+		}
+		printk ("\n");
+	}
+	if (np->rx_debug == 7) {
+		printk (" In rcv_pkt(), entry %d status %4.4x %4.4x.\n",
+			entry, (u32) (np->rx_ring[entry].status >> 32),
+			(u32) np->rx_ring[entry].status);
+	}
+
+}
+
+static inline void
+debug_pkt_dump (struct netdev_private *np, int pkt_len)
+{
+	int i;
+	struct netdev_desc *desc = np->rx_head_desc;
+	unsigned char *pchar;
+	unsigned char *phead;
+	u64 frame_status = le64_to_cpu (desc->status);
+
+	if (np->rx_debug == 4) {
+		printk ("  rcv_pkt: status was %4.4x %4.4x.\n",
+			(u32) (frame_status >> 32), (u32) frame_status);
+	}
+	if (np->rx_debug == 7) {
+		phead = le64desc_to_virt ((desc->fraginfo & 0xffffffffff));
+		for (pchar = phead, i = 0; i < pkt_len; i++, pchar++) {
+			printk ("%02x ", *pchar);
+			if ((i + 1) % 20 == 0)
+				printk ("\n");
+		}
+	}
+}
+#else
+#define DEBUG_TFD_DUMP(x) {}
+#define DEBUG_RFD_DUMP(x,flag) {}
+#define DEBUG_PKT_DUMP(x,len) {}
+#define DEBUG_PRINT() {}
+#endif
+
+#endif /* __DL2K_H__ */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- v2.4.6/linux/drivers/net/dmfe.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/dmfe.c	Wed Jul  4 14:41:33 2001
@@ -127,8 +127,8 @@
 #define DMFE_TXTH_1K	0xC000		/* TX TH 1K  byte */
 
 #define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT (HZ * 1.5)	/* tx packet time-out time 1.5 s" */
-#define DMFE_TX_KICK 	(HZ * 0.5)	/* tx packet Kick-out time 0.5 s" */
+#define DMFE_TX_TIMEOUT ((3*HZ)/2)	/* tx packet time-out time 1.5 s" */
+#define DMFE_TX_KICK 	(HZ/2)	/* tx packet Kick-out time 0.5 s" */
 
 #define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR "<DMFE>: %s %lx\n", (msg), (long) (value))
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.4.6/linux/drivers/net/epic100.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/epic100.c	Sun Jul  8 13:17:30 2001
@@ -1174,8 +1174,6 @@
 
 			pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
 					    ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
-					 ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			if (pkt_len > PKT_BUF_SZ - 4) {
 				printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
 					   "%d bytes.\n",
@@ -1196,6 +1194,9 @@
 					   pkt_len);
 #endif
 			} else {
+				pci_unmap_single(ep->pci_dev, 
+					ep->rx_ring[entry].bufaddr, 
+					ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 				skb_put(skb = ep->rx_skbuff[entry], pkt_len);
 				ep->rx_skbuff[entry] = NULL;
 			}
diff -u --recursive --new-file v2.4.6/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.4.6/linux/drivers/net/eql.c	Mon May 14 23:55:12 2001
+++ linux/drivers/net/eql.c	Wed Jul  4 14:41:33 2001
@@ -16,9 +16,6 @@
  *    Phone: 1-703-847-0040 ext 103
  */
 
-static const char *version = 
-	"Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n";
-
 /*
  * Sources:
  *   skeleton.c by Donald Becker.
@@ -124,6 +121,8 @@
 
 #include <asm/uaccess.h>
 
+static const char version[] __initdata = 
+	"Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n";
 
 #ifndef EQL_DEBUG
 /* #undef EQL_DEBUG      -* print nothing at all, not even a boot-banner */
@@ -360,9 +359,9 @@
 #endif
 		skb->dev = slave_dev;
 		skb->priority = 1;
+		slave->bytes_queued += skb->len; 
 		dev_queue_xmit (skb);
 		eql->stats->tx_packets++;
-		slave->bytes_queued += skb->len; 
 	}
 	else
 	{
diff -u --recursive --new-file v2.4.6/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.4.6/linux/drivers/net/eth16i.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/eth16i.c	Wed Jul  4 14:41:33 2001
@@ -354,21 +354,21 @@
 #define RESET                  ID_ROM_0
 
 /* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] = {
+static unsigned int eth16i_portlist[] __initdata = {
 	0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 
 };
 
-static unsigned int eth32i_portlist[] = { 
+static unsigned int eth32i_portlist[] __initdata = { 
 	0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
 	0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 
 };
 
 /* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
+static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 };
 #define NUM_OF_ISA_IRQS    4
 
 /* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };  
+static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };  
 #define EISA_IRQ_REG	0xc89
 #define NUM_OF_EISA_IRQS   8
 
@@ -434,7 +434,7 @@
 
 static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
 
-static char cardname[] = "ICL EtherTeam 16i/32";
+static char cardname[] __initdata = "ICL EtherTeam 16i/32";
 
 int __init eth16i_probe(struct net_device *dev)
 {
@@ -832,7 +832,7 @@
 }
 #endif
 
-static int eth16i_get_irq(int ioaddr)
+static int __init eth16i_get_irq(int ioaddr)
 {
 	unsigned char cbyte;
 
@@ -850,7 +850,7 @@
 	}
 }
 
-static int eth16i_check_signature(int ioaddr)
+static int __init eth16i_check_signature(int ioaddr)
 {
 	int i;
 	unsigned char creg[4] = { 0 };
diff -u --recursive --new-file v2.4.6/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
--- v2.4.6/linux/drivers/net/ioc3-eth.c	Wed May 16 10:25:38 2001
+++ linux/drivers/net/ioc3-eth.c	Wed Jul  4 14:41:33 2001
@@ -5,43 +5,26 @@
  *
  * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
  *
- * Copyright (C) 1999, 2000 Ralf Baechle
- * Copyright (C) 1995, 1999, 2000 by Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2000, 2001 Ralf Baechle
+ * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
  *
- * Reporting bugs:
- *
- * If you find problems with this drivers, then if possible do the
- * following.  Hook up a terminal to the MSC port, send an NMI to the CPUs
- * by typing ^Tnmi (where ^T stands for <CTRL>-T).  You'll see something
- * like:
- * 1A 000: 
- * 1A 000: *** NMI while in Kernel and no NMI vector installed on node 0
- * 1A 000: *** Error EPC: 0xffffffff800265e4 (0xffffffff800265e4)
- * 1A 000: *** Press ENTER to continue.
- *
- * Next enter the command ``lw i:0x86000f0 0x18'' and include this
- * commands output which will look like below with your bugreport.
- *
- * 1A 000: POD MSC Dex> lw i:0x86000f0 0x18
- * 1A 000: 92000000086000f0: 0021f28c 00000000 00000000 00000000
- * 1A 000: 9200000008600100: a5000000 01cde000 00000000 000004e0
- * 1A 000: 9200000008600110: 00000650 00000000 00110b15 00000000
- * 1A 000: 9200000008600120: 006d0005 77bbca0a a5000000 01ce0000
- * 1A 000: 9200000008600130: 80000500 00000500 00002538 05690008
- * 1A 000: 9200000008600140: 00000000 00000000 000003e1 0000786d
+ * References:
+ *  o IOC3 ASIC specification 4.51, 1996-04-18
+ *  o IEEE 802.3 specification, 2000 edition
+ *  o DP38840A Specification, National Semiconductor, March 1997
  *
  * To do:
  *
- *  - Handle allocation failures in ioc3_alloc_skb() more gracefully.
- *  - Handle allocation failures in ioc3_init_rings().
- *  - Use prefetching for large packets.  What is a good lower limit for
+ *  o Handle allocation failures in ioc3_alloc_skb() more gracefully.
+ *  o Handle allocation failures in ioc3_init_rings().
+ *  o Use prefetching for large packets.  What is a good lower limit for
  *    prefetching?
- *  - We're probably allocating a bit too much memory.
- *  - Workarounds for various PHYs.
- *  - Proper autonegotiation.
- *  - What exactly is net_device_stats.tx_dropped supposed to count?
- *  - Use hardware checksums.
- *  - Convert to using the PCI infrastructure / IOC3 meta driver.
+ *  o We're probably allocating a bit too much memory.
+ *  o Use hardware checksums.
+ *  o Convert to using a IOC3 meta driver.
+ *  o Which PHYs might possibly be attached to the IOC3 in real live,
+ *    which workarounds are required for them?  Do we ever have Lucent's?
+ *  o For the 2.5 branch kill the mii-tool ioctls.
  */
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -51,13 +34,23 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 
+#ifdef CONFIG_SERIAL
+#include <linux/serial.h>
+#include <asm/serial.h>
+#define IOC3_BAUD (22000000 / (3*16))
+#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#endif
+
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/skbuff.h>
+#include <linux/mii.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/uaccess.h>
 #include <asm/sn/types.h>
 #include <asm/sn/sn0/addrs.h>
 #include <asm/sn/sn0/hubni.h>
@@ -68,14 +61,14 @@
 #include <asm/pci/bridge.h>
 
 /*
- * 32 RX buffers.  This is tunable in the range of 16 <= x < 512.  The
+ * 64 RX buffers.  This is tunable in the range of 16 <= x < 512.  The
  * value must be a power of two.
  */
 #define RX_BUFFS 64
 
 /*
- * Private ioctls that de facto are well known and used for examply
- * by mii-tool.
+ * Private ioctls that de facto are well known and used for example
+ * by mii-tool.  These are deprecated and will go away in 2.5.0.
  */
 #define SIOCGMIIPHY (SIOCDEVPRIVATE)	/* Read from current PHY */
 #define SIOCGMIIREG (SIOCDEVPRIVATE+1)	/* Read any PHY register */
@@ -85,6 +78,14 @@
 #define SIOCGPARAMS (SIOCDEVPRIVATE+3)	/* Read operational parameters */
 #define SIOCSPARAMS (SIOCDEVPRIVATE+4)	/* Set operational parameters */
 
+/* Timer state engine. */
+enum ioc3_timer_state {
+	arbwait  = 0,	/* Waiting for auto negotiation to complete.          */
+	lupwait  = 1,	/* Auto-neg complete, awaiting link-up status.        */
+	ltrywait = 2,	/* Forcing try of all modes, from fastest to slowest. */
+	asleep   = 3,	/* Time inactive.                                     */
+};
+
 /* Private per NIC data of the driver.  */
 struct ioc3_private {
 	struct ioc3 *regs;
@@ -100,8 +101,20 @@
 	int tx_pi;			/* TX producer index */
 	int txqlen;
 	u32 emcr, ehar_h, ehar_l;
-	struct timer_list negtimer;
 	spinlock_t ioc3_lock;
+	struct net_device *dev;
+
+	/* Members used by autonegotiation  */
+	struct timer_list ioc3_timer;
+	enum ioc3_timer_state timer_state; /* State of auto-neg timer.	   */
+	unsigned int timer_ticks;	/* Number of clicks at each state  */
+	unsigned short sw_bmcr;		/* sw copy of MII config register  */
+	unsigned short sw_bmsr;		/* sw copy of MII status register  */
+	unsigned short sw_physid1;	/* sw copy of PHYSID1		   */
+	unsigned short sw_physid2;	/* sw copy of PHYSID2		   */
+	unsigned short sw_advertise;	/* sw copy of ADVERTISE		   */
+	unsigned short sw_lpa;		/* sw copy of LPA		   */
+	unsigned short sw_csconfig;	/* sw copy of CSCONFIG		   */
 };
 
 static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -109,8 +122,8 @@
 static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void ioc3_timeout(struct net_device *dev);
 static inline unsigned int ioc3_hash(const unsigned char *addr);
-static inline void ioc3_stop(struct net_device *dev);
-static void ioc3_init(struct net_device *dev);
+static inline void ioc3_stop(struct ioc3_private *ip);
+static void ioc3_init(struct ioc3_private *ip);
 
 static const char ioc3_str[] = "IOC3 Ethernet";
 
@@ -341,8 +354,9 @@
 /*
  * Read the NIC (Number-In-a-Can) device.
  */
-static void ioc3_get_eaddr(struct net_device *dev, struct ioc3 *ioc3)
+static void ioc3_get_eaddr(struct ioc3_private *ip)
 {
+	struct ioc3 *ioc3 = ip->regs;
 	u8 nic[14];
 	int i;
 	int tries = 2; /* There may be some problem with the battery?  */
@@ -370,7 +384,7 @@
 
 	printk("Ethernet address is ");
 	for (i = 2; i < 8; i++) {
-		dev->dev_addr[i - 2] = nic[i];
+		ip->dev->dev_addr[i - 2] = nic[i];
 		printk("%02x", nic[i]);
 		if (i < 7)
 			printk(":");
@@ -378,10 +392,15 @@
 	printk(".\n");
 }
 
-/* Caller must hold the ioc3_lock ever for MII readers.  This is also
-   used to protect the transmitter side but it's low contention.  */
-static u16 mii_read(struct ioc3 *ioc3, int phy, int reg)
+/*
+ * Caller must hold the ioc3_lock ever for MII readers.  This is also
+ * used to protect the transmitter side but it's low contention.
+ */
+static u16 mii_read(struct ioc3_private *ip, int reg)
 {
+	struct ioc3 *ioc3 = ip->regs;
+	int phy = ip->phy;
+
 	while (ioc3->micr & MICR_BUSY);
 	ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG;
 	while (ioc3->micr & MICR_BUSY);
@@ -389,16 +408,18 @@
 	return ioc3->midr_r & MIDR_DATA_MASK;
 }
 
-static void mii_write(struct ioc3 *ioc3, int phy, int reg, u16 data)
+static void mii_write(struct ioc3_private *ip, int reg, u16 data)
 {
+	struct ioc3 *ioc3 = ip->regs;
+	int phy = ip->phy;
+
 	while (ioc3->micr & MICR_BUSY);
 	ioc3->midr_w = data;
 	ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg;
 	while (ioc3->micr & MICR_BUSY);
 }
 
-static int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip,
-                         struct ioc3 *ioc3);
+static int ioc3_mii_init(struct ioc3_private *ip);
 
 static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
 {
@@ -410,9 +431,10 @@
 }
 
 static inline void
-ioc3_rx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3)
+ioc3_rx(struct ioc3_private *ip)
 {
 	struct sk_buff *skb, *new_skb;
+	struct ioc3 *ioc3 = ip->regs;
 	int rx_entry, n_entry, len;
 	struct ioc3_erxbuf *rxb;
 	unsigned long *rxr;
@@ -429,12 +451,9 @@
 	while (w0 & ERXBUF_V) {
 		err = rxb->err;				/* It's valid ...  */
 		if (err & ERXBUF_GOODPKT) {
-			len = (w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff;
+			len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
 			skb_trim(skb, len);
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-
-			ip->rx_skbs[rx_entry] = NULL;	/* Poison  */
+			skb->protocol = eth_type_trans(skb, ip->dev);
 
 			new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
 			if (!new_skb) {
@@ -444,15 +463,18 @@
 				new_skb = skb;
 				goto next;
 			}
+			netif_rx(skb);
 
-			new_skb->dev = dev;
+			ip->rx_skbs[rx_entry] = NULL;	/* Poison  */
+
+			new_skb->dev = ip->dev;
 
 			/* Because we reserve afterwards. */
 			skb_put(new_skb, (1664 + RX_OFFSET));
 			rxb = (struct ioc3_erxbuf *) new_skb->data;
 			skb_reserve(new_skb, RX_OFFSET);
 
-			dev->last_rx = jiffies;
+			ip->dev->last_rx = jiffies;
 			ip->stats.rx_packets++;		/* Statistics */
 			ip->stats.rx_bytes += len;
 		} else {
@@ -485,9 +507,10 @@
 }
 
 static inline void
-ioc3_tx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3)
+ioc3_tx(struct ioc3_private *ip)
 {
 	unsigned long packets, bytes;
+	struct ioc3 *ioc3 = ip->regs;
 	int tx_entry, o_entry;
 	struct sk_buff *skb;
 	u32 etcir;
@@ -518,7 +541,7 @@
 	ip->txqlen -= packets;
 
 	if (ip->txqlen < 128)
-		netif_wake_queue(dev);
+		netif_wake_queue(ip->dev);
 
 	ip->tx_ci = o_entry;
 	spin_unlock(&ip->ioc3_lock);
@@ -532,31 +555,27 @@
  * also consider to take the interface down.
  */
 static void
-ioc3_error(struct net_device *dev, struct ioc3_private *ip,
-           struct ioc3 *ioc3, u32 eisr)
+ioc3_error(struct ioc3_private *ip, u32 eisr)
 {
-	if (eisr & EISR_RXOFLO) {
-		printk(KERN_ERR "%s: RX overflow.\n", dev->name);
-	}
-	if (eisr & EISR_RXBUFOFLO) {
-		printk(KERN_ERR "%s: RX buffer overflow.\n", dev->name);
-	}
-	if (eisr & EISR_RXMEMERR) {
-		printk(KERN_ERR "%s: RX PCI error.\n", dev->name);
-	}
-	if (eisr & EISR_RXPARERR) {
-		printk(KERN_ERR "%s: RX SSRAM parity error.\n", dev->name);
-	}
-	if (eisr & EISR_TXBUFUFLO) {
-		printk(KERN_ERR "%s: TX buffer underflow.\n", dev->name);
-	}
-	if (eisr & EISR_TXMEMERR) {
-		printk(KERN_ERR "%s: TX PCI error.\n", dev->name);
-	}
+	struct net_device *dev = ip->dev;
+	unsigned char *iface = dev->name;
 
-	ioc3_stop(dev);
-	ioc3_init(dev);
-	ioc3_mii_init(dev, ip, ioc3);
+	if (eisr & EISR_RXOFLO)
+		printk(KERN_ERR "%s: RX overflow.\n", iface);
+	if (eisr & EISR_RXBUFOFLO)
+		printk(KERN_ERR "%s: RX buffer overflow.\n", iface);
+	if (eisr & EISR_RXMEMERR)
+		printk(KERN_ERR "%s: RX PCI error.\n", iface);
+	if (eisr & EISR_RXPARERR)
+		printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface);
+	if (eisr & EISR_TXBUFUFLO)
+		printk(KERN_ERR "%s: TX buffer underflow.\n", iface);
+	if (eisr & EISR_TXMEMERR)
+		printk(KERN_ERR "%s: TX PCI error.\n", iface);
+
+	ioc3_stop(ip);
+	ioc3_init(ip);
+	ioc3_mii_init(ip);
 
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
@@ -566,7 +585,7 @@
    after the Tx thread.  */
 static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs)
 {
-	struct net_device *dev = _dev;
+	struct net_device *dev = (struct net_device *)_dev;
 	struct ioc3_private *ip = dev->priv;
 	struct ioc3 *ioc3 = ip->regs;
 	const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
@@ -582,53 +601,500 @@
 
 		if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
 		            EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
-			ioc3_error(dev, ip, ioc3, eisr);
+			ioc3_error(ip, eisr);
 		if (eisr & EISR_RXTIMERINT)
-			ioc3_rx(dev, ip, ioc3);
+			ioc3_rx(ip);
 		if (eisr & EISR_TXEXPLICIT)
-			ioc3_tx(dev, ip, ioc3);
+			ioc3_tx(ip);
 
 		eisr = ioc3->eisr & enabled;
 	}
 }
 
-static void negotiate(unsigned long data)
+/*
+ * Auto negotiation.  The scheme is very simple.  We have a timer routine that
+ * keeps watching the auto negotiation process as it progresses.  The DP83840
+ * is first told to start doing it's thing, we set up the time and place the
+ * timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen.  For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the IOC3 to speak
+ * the most efficient protocol we could get a clean link for.  The priority
+ * for link configurations, highest first is:
+ *
+ *     100 Base-T Full Duplex
+ *     100 Base-T Half Duplex
+ *     10 Base-T Full Duplex
+ *     10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected.  This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840.  When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+static int ioc3_try_next_permutation(struct ioc3_private *ip)
+{
+	ip->sw_bmcr = mii_read(ip, MII_BMCR);
+
+	/* Downgrade from full to half duplex.  Only possible via ethtool.  */
+	if (ip->sw_bmcr & BMCR_FULLDPLX) {
+		ip->sw_bmcr &= ~BMCR_FULLDPLX;
+		mii_write(ip, MII_BMCR, ip->sw_bmcr);
+
+		return 0;
+	}
+
+	/* Downgrade from 100 to 10. */
+	if (ip->sw_bmcr & BMCR_SPEED100) {
+		ip->sw_bmcr &= ~BMCR_SPEED100;
+		mii_write(ip, MII_BMCR, ip->sw_bmcr);
+
+		return 0;
+	}
+
+	/* We've tried everything. */
+	return -1;
+}
+
+static void
+ioc3_display_link_mode(struct ioc3_private *ip)
+{
+	char *tmode = "";
+
+	ip->sw_lpa = mii_read(ip, MII_LPA);
+
+	if (ip->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
+		if (ip->sw_lpa & LPA_100FULL)
+			tmode = "100Mb/s, Full Duplex";
+		else
+			tmode = "100Mb/s, Half Duplex";
+	} else {
+		if (ip->sw_lpa & LPA_10FULL)
+			tmode = "10Mb/s, Full Duplex";
+		else
+			tmode = "10Mb/s, Half Duplex";
+	}
+
+	printk(KERN_INFO "%s: Link is up at %s.\n", ip->dev->name, tmode);
+}
+
+static void
+ioc3_display_forced_link_mode(struct ioc3_private *ip)
+{
+	char *speed = "", *duplex = "";
+
+	ip->sw_bmcr = mii_read(ip, MII_BMCR);
+	if (ip->sw_bmcr & BMCR_SPEED100)
+		speed = "100Mb/s, ";
+	else
+		speed = "10Mb/s, ";
+	if (ip->sw_bmcr & BMCR_FULLDPLX)
+		duplex = "Full Duplex.\n";
+	else
+		duplex = "Half Duplex.\n";
+
+	printk(KERN_INFO "%s: Link has been forced up at %s%s", ip->dev->name,
+	       speed, duplex);
+}
+
+static int ioc3_set_link_modes(struct ioc3_private *ip)
 {
-	struct net_device *dev = (struct net_device *) data;
-	struct ioc3_private *ip = dev->priv;
 	struct ioc3 *ioc3 = ip->regs;
+	int full;
+
+	/*
+	 * All we care about is making sure the bigmac tx_cfg has a
+	 * proper duplex setting.
+	 */
+	if (ip->timer_state == arbwait) {
+		ip->sw_lpa = mii_read(ip, MII_LPA);
+		if (!(ip->sw_lpa & (LPA_10HALF | LPA_10FULL |
+		                    LPA_100HALF | LPA_100FULL)))
+			goto no_response;
+		if (ip->sw_lpa & LPA_100FULL)
+			full = 1;
+		else if (ip->sw_lpa & LPA_100HALF)
+			full = 0;
+		else if (ip->sw_lpa & LPA_10FULL)
+			full = 1;
+		else
+			full = 0;
+	} else {
+		/* Forcing a link mode. */
+		ip->sw_bmcr = mii_read(ip, MII_BMCR);
+		if (ip->sw_bmcr & BMCR_FULLDPLX)
+			full = 1;
+		else
+			full = 0;
+	}
 
-	mod_timer(&ip->negtimer, jiffies + 20 * HZ);
+	if (full)
+		ip->emcr |= EMCR_DUPLEX;
+	else
+		ip->emcr &= ~EMCR_DUPLEX;
+
+	ioc3->emcr = ip->emcr;
+	ioc3->emcr;
+
+	return 0;
+
+no_response:
+
+	return 1;
 }
 
-static int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip,
-                         struct ioc3 *ioc3)
+static int is_lucent_phy(struct ioc3_private *ip)
 {
-	u16 word, mii0;
-	int i, phy;
+	unsigned short mr2, mr3;
+	int ret = 0;
+
+	mr2 = mii_read(ip, MII_PHYSID1);
+	mr3 = mii_read(ip, MII_PHYSID2);
+	if ((mr2 & 0xffff) == 0x0180 && ((mr3 & 0xffff) >> 10) == 0x1d) {
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static void ioc3_timer(unsigned long data)
+{
+	struct ioc3_private *ip = (struct ioc3_private *) data;
+	int restart_timer = 0;
+
+	ip->timer_ticks++;
+	switch (ip->timer_state) {
+	case arbwait:
+		/*
+		 * Only allow for 5 ticks, thats 10 seconds and much too
+		 * long to wait for arbitration to complete.
+		 */
+		if (ip->timer_ticks >= 10) {
+			/* Enter force mode. */
+	do_force_mode:
+			ip->sw_bmcr = mii_read(ip, MII_BMCR);
+			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+			       " trying force link mode\n", ip->dev->name);
+			ip->sw_bmcr = BMCR_SPEED100;
+			mii_write(ip, MII_BMCR, ip->sw_bmcr);
+
+			if (!is_lucent_phy(ip)) {
+				/*
+				 * OK, seems we need do disable the transceiver
+				 * for the first tick to make sure we get an
+				 * accurate link state at the second tick.
+				 */
+				ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);
+				ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+				mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
+			}
+			ip->timer_state = ltrywait;
+			ip->timer_ticks = 0;
+			restart_timer = 1;
+		} else {
+			/* Anything interesting happen? */
+			ip->sw_bmsr = mii_read(ip, MII_BMSR);
+			if (ip->sw_bmsr & BMSR_ANEGCOMPLETE) {
+				int ret;
+
+				/* Just what we've been waiting for... */
+				ret = ioc3_set_link_modes(ip);
+				if (ret) {
+					/* Ooops, something bad happened, go to
+					 * force mode.
+					 *
+					 * XXX Broken hubs which don't support
+					 * XXX 802.3u auto-negotiation make this
+					 * XXX happen as well.
+					 */
+					goto do_force_mode;
+				}
+
+				/*
+				 * Success, at least so far, advance our state
+				 * engine.
+				 */
+				ip->timer_state = lupwait;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lupwait:
+		/*
+		 * Auto negotiation was successful and we are awaiting a
+		 * link up status.  I have decided to let this timer run
+		 * forever until some sort of error is signalled, reporting
+		 * a message to the user at 10 second intervals.
+		 */
+		ip->sw_bmsr = mii_read(ip, MII_BMSR);
+		if (ip->sw_bmsr & BMSR_LSTATUS) {
+			/*
+			 * Wheee, it's up, display the link mode in use and put
+			 * the timer to sleep.
+			 */
+			ioc3_display_link_mode(ip);
+			ip->timer_state = asleep;
+			restart_timer = 0;
+		} else {
+			if (ip->timer_ticks >= 10) {
+				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+				       "not completely up.\n", ip->dev->name);
+				ip->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
 
+	case ltrywait:
+		/*
+		 * Making the timeout here too long can make it take
+		 * annoyingly long to attempt all of the link mode
+		 * permutations, but then again this is essentially
+		 * error recovery code for the most part.
+		 */
+		ip->sw_bmsr = mii_read(ip, MII_BMSR);
+		ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);
+		if (ip->timer_ticks == 1) {
+			if (!is_lucent_phy(ip)) {
+				/*
+				 * Re-enable transceiver, we'll re-enable the
+				 * transceiver next tick, then check link state
+				 * on the following tick.
+				 */
+				ip->sw_csconfig |= CSCONFIG_TCVDISAB;
+				mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
+			}
+			restart_timer = 1;
+			break;
+		}
+		if (ip->timer_ticks == 2) {
+			if (!is_lucent_phy(ip)) {
+				ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+				mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
+			}
+			restart_timer = 1;
+			break;
+		}
+		if (ip->sw_bmsr & BMSR_LSTATUS) {
+			/* Force mode selection success. */
+			ioc3_display_forced_link_mode(ip);
+			ioc3_set_link_modes(ip);  /* XXX error? then what? */
+			ip->timer_state = asleep;
+			restart_timer = 0;
+		} else {
+			if (ip->timer_ticks >= 4) { /* 6 seconds or so... */
+				int ret;
+
+				ret = ioc3_try_next_permutation(ip);
+				if (ret == -1) {
+					/*
+					 * Aieee, tried them all, reset the
+					 * chip and try all over again.
+					 */
+					printk(KERN_NOTICE "%s: Link down, "
+					       "cable problem?\n",
+					       ip->dev->name);
+
+					ioc3_init(ip);
+					return;
+				}
+				if (!is_lucent_phy(ip)) {
+					ip->sw_csconfig = mii_read(ip,
+					                    MII_CSCONFIG);
+					ip->sw_csconfig |= CSCONFIG_TCVDISAB;
+					mii_write(ip, MII_CSCONFIG,
+					          ip->sw_csconfig);
+				}
+				ip->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case asleep:
+	default:
+		/* Can't happens.... */
+		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+		       "one anyways!\n", ip->dev->name);
+		restart_timer = 0;
+		ip->timer_ticks = 0;
+		ip->timer_state = asleep; /* foo on you */
+		break;
+	};
+
+	if (restart_timer) {
+		ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */
+		add_timer(&ip->ioc3_timer);
+	}
+}
+
+static void
+ioc3_start_auto_negotiation(struct ioc3_private *ip, struct ethtool_cmd *ep)
+{
+	int timeout;
+
+	/* Read all of the registers we are interested in now. */
+	ip->sw_bmsr      = mii_read(ip, MII_BMSR);
+	ip->sw_bmcr      = mii_read(ip, MII_BMCR);
+	ip->sw_physid1   = mii_read(ip, MII_PHYSID1);
+	ip->sw_physid2   = mii_read(ip, MII_PHYSID2);
+
+	/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
+
+	ip->sw_advertise = mii_read(ip, MII_ADVERTISE);
+	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+		/* Advertise everything we can support. */
+		if (ip->sw_bmsr & BMSR_10HALF)
+			ip->sw_advertise |= ADVERTISE_10HALF;
+		else
+			ip->sw_advertise &= ~ADVERTISE_10HALF;
+
+		if (ip->sw_bmsr & BMSR_10FULL)
+			ip->sw_advertise |= ADVERTISE_10FULL;
+		else
+			ip->sw_advertise &= ~ADVERTISE_10FULL;
+		if (ip->sw_bmsr & BMSR_100HALF)
+			ip->sw_advertise |= ADVERTISE_100HALF;
+		else
+			ip->sw_advertise &= ~ADVERTISE_100HALF;
+		if (ip->sw_bmsr & BMSR_100FULL)
+			ip->sw_advertise |= ADVERTISE_100FULL;
+		else
+			ip->sw_advertise &= ~ADVERTISE_100FULL;
+		mii_write(ip, MII_ADVERTISE, ip->sw_advertise);
+
+		/*
+		 * XXX Currently no IOC3 card I know off supports 100BaseT4,
+		 * XXX and this is because the DP83840 does not support it,
+		 * XXX changes XXX would need to be made to the tx/rx logic in
+		 * XXX the driver as well so I completely skip checking for it
+		 * XXX in the BMSR for now.
+		 */
+
+#ifdef AUTO_SWITCH_DEBUG
+		ASD(("%s: Advertising [ ", ip->dev->name));
+		if (ip->sw_advertise & ADVERTISE_10HALF)
+			ASD(("10H "));
+		if (ip->sw_advertise & ADVERTISE_10FULL)
+			ASD(("10F "));
+		if (ip->sw_advertise & ADVERTISE_100HALF)
+			ASD(("100H "));
+		if (ip->sw_advertise & ADVERTISE_100FULL)
+			ASD(("100F "));
+#endif
+
+		/* Enable Auto-Negotiation, this is usually on already... */
+		ip->sw_bmcr |= BMCR_ANENABLE;
+		mii_write(ip, MII_BMCR, ip->sw_bmcr);
+
+		/* Restart it to make sure it is going. */
+		ip->sw_bmcr |= BMCR_ANRESTART;
+		mii_write(ip, MII_BMCR, ip->sw_bmcr);
+
+		/* BMCR_ANRESTART self clears when the process has begun. */
+
+		timeout = 64;  /* More than enough. */
+		while (--timeout) {
+			ip->sw_bmcr = mii_read(ip, MII_BMCR);
+			if (!(ip->sw_bmcr & BMCR_ANRESTART))
+				break; /* got it. */
+			udelay(10);
+		}
+		if (!timeout) {
+			printk(KERN_ERR "%s: IOC3 would not start auto "
+			       "negotiation BMCR=0x%04x\n",
+			       ip->dev->name, ip->sw_bmcr);
+			printk(KERN_NOTICE "%s: Performing force link "
+			       "detection.\n", ip->dev->name);
+			goto force_link;
+		} else {
+			ip->timer_state = arbwait;
+		}
+	} else {
+force_link:
+		/*
+		 * Force the link up, trying first a particular mode.  Either
+		 * we are here at the request of ethtool or because the IOC3
+		 * would not start to autoneg.
+		 */
+
+		/*
+		 * Disable auto-negotiation in BMCR, enable the duplex and
+		 * speed setting, init the timer state machine, and fire it off.
+		 */
+		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+			ip->sw_bmcr = BMCR_SPEED100;
+		} else {
+			if (ep->speed == SPEED_100)
+				ip->sw_bmcr = BMCR_SPEED100;
+			else
+				ip->sw_bmcr = 0;
+			if (ep->duplex == DUPLEX_FULL)
+				ip->sw_bmcr |= BMCR_FULLDPLX;
+		}
+		mii_write(ip, MII_BMCR, ip->sw_bmcr);
+
+		if (!is_lucent_phy(ip)) {
+			/*
+			 * OK, seems we need do disable the transceiver for the
+			 * first tick to make sure we get an accurate link
+			 * state at the second tick.
+			 */
+			ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);
+			ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+			mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
+		}
+		ip->timer_state = ltrywait;
+	}
+
+	del_timer(&ip->ioc3_timer);
+	ip->timer_ticks = 0;
+	ip->ioc3_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
+	ip->ioc3_timer.data = (unsigned long) ip;
+	ip->ioc3_timer.function = &ioc3_timer;
+	add_timer(&ip->ioc3_timer);
+}
+
+static int ioc3_mii_init(struct ioc3_private *ip)
+{
+	int i, found;
+	u16 word;
+
+	found = 0;
 	spin_lock_irq(&ip->ioc3_lock);
-	phy = -1;
 	for (i = 0; i < 32; i++) {
-		word = mii_read(ioc3, i, 2);
+		ip->phy = i;
+		word = mii_read(ip, 2);
 		if ((word != 0xffff) && (word != 0x0000)) {
-			phy = i;
+			found = 1;
 			break;			/* Found a PHY		*/
 		}
 	}
-	if (phy == -1) {
+	if (!found) {
 		spin_unlock_irq(&ip->ioc3_lock);
 		return -ENODEV;
 	}
-	ip->phy = phy;
 
-	/* Autonegotiate 100mbit and fullduplex. */
-	mii0 = mii_read(ioc3, ip->phy, 0);
-	mii_write(ioc3, ip->phy, 0, mii0 | 0x3100);
-
-	ip->negtimer.function = &negotiate;
-	ip->negtimer.data = (unsigned long) dev;
-	mod_timer(&ip->negtimer, jiffies);	/* Run it now  */
+	ioc3_start_auto_negotiation(ip, NULL);		// XXX ethtool
 
 	spin_unlock_irq(&ip->ioc3_lock);
 
@@ -808,13 +1274,15 @@
 	}
 }
 
-static void ioc3_init(struct net_device *dev)
+static void ioc3_init(struct ioc3_private *ip)
 {
-	struct ioc3_private *ip = dev->priv;
+	struct net_device *dev = ip->dev;
 	struct ioc3 *ioc3 = ip->regs;
 
+	del_timer(&ip->ioc3_timer);		/* Kill if running	*/
+
 	ioc3->emcr = EMCR_RST;			/* Reset		*/
-	ioc3->emcr;				/* flush WB		*/
+	ioc3->emcr;				/* Flush WB		*/
 	udelay(4);				/* Give it time ...	*/
 	ioc3->emcr = 0;
 	ioc3->emcr;
@@ -832,7 +1300,7 @@
 	ioc3->ehar_l = ip->ehar_l;
 	ioc3->ersr = 42;			/* XXX should be random */
 
-	ioc3_init_rings(dev, ip, ioc3);
+	ioc3_init_rings(ip->dev, ip, ioc3);
 
 	ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN |
 	             EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN;
@@ -843,9 +1311,8 @@
 	ioc3->eier;
 }
 
-static inline void ioc3_stop(struct net_device *dev)
+static inline void ioc3_stop(struct ioc3_private *ip)
 {
-	struct ioc3_private *ip = dev->priv;
 	struct ioc3 *ioc3 = ip->regs;
 
 	ioc3->emcr = 0;				/* Shutup */
@@ -856,19 +1323,17 @@
 static int
 ioc3_open(struct net_device *dev)
 {
-	struct ioc3_private *ip;
+	struct ioc3_private *ip = dev->priv;
 
-	if (request_irq(dev->irq, ioc3_interrupt, 0, ioc3_str, dev)) {
+	if (request_irq(dev->irq, ioc3_interrupt, SA_SHIRQ, ioc3_str, dev)) {
 		printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
 
 		return -EAGAIN;
 	}
 
-	ip = dev->priv;
-
 	ip->ehar_h = 0;
 	ip->ehar_l = 0;
-	ioc3_init(dev);
+	ioc3_init(ip);
 
 	netif_start_queue(dev);
 	return 0;
@@ -879,89 +1344,132 @@
 {
 	struct ioc3_private *ip = dev->priv;
 
-	del_timer(&ip->negtimer);
+	del_timer(&ip->ioc3_timer);
+
 	netif_stop_queue(dev);
 
-	ioc3_stop(dev);					/* Flush */
+	ioc3_stop(ip);
 	free_irq(dev->irq, dev);
 
 	ioc3_free_rings(ip);
 	return 0;
 }
 
+/*
+ * MENET cards have four IOC3 chips, which are attached to two sets of
+ * PCI slot resources each: the primary connections are on slots
+ * 0..3 and the secondaries are on 4..7
+ *
+ * All four ethernets are brought out to connectors; six serial ports
+ * (a pair from each of the first three IOC3s) are brought out to
+ * MiniDINs; all other subdevices are left swinging in the wind, leave
+ * them disabled.
+ */
+static inline int ioc3_is_menet(struct pci_dev *pdev)
+{
+	struct pci_dev *dev;
+
+	return pdev->bus->parent == NULL
+	       && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(0, 0)))
+	       && dev->vendor == PCI_VENDOR_ID_SGI
+	       && dev->device == PCI_DEVICE_ID_SGI_IOC3
+	       && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(1, 0)))
+	       && dev->vendor == PCI_VENDOR_ID_SGI
+	       && dev->device == PCI_DEVICE_ID_SGI_IOC3
+	       && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(2, 0)))
+	       && dev->vendor == PCI_VENDOR_ID_SGI
+	       && dev->device == PCI_DEVICE_ID_SGI_IOC3;
+}
+
+static void inline ioc3_serial_probe(struct pci_dev *pdev,
+				struct ioc3 *ioc3)
+{
+	struct serial_struct req;
+
+	/*
+	 * We need to recognice and treat the fourth MENET serial as it
+	 * does not have an SuperIO chip attached to it, therefore attempting
+	 * to access it will result in bus errors.  We call something an
+	 * MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3
+	 * in it.  This is paranoid but we want to avoid blowing up on a
+	 * showhorn PCI box that happens to have 4 IOC3 cards in it so it's
+	 * not paranoid enough ...
+	 */
+	if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
+		return;
+
+	/* Register to interrupt zero because we share the interrupt with
+	   the serial driver which we don't properly support yet.  */
+	memset(&req, 0, sizeof(req));
+	req.irq             = 0;
+	req.flags           = IOC3_COM_FLAGS;
+	req.io_type         = SERIAL_IO_MEM;
+	req.iomem_reg_shift = 0;
+	req.baud_base       = IOC3_BAUD;
+
+	req.iomem_base      = (unsigned char *) &ioc3->sregs.uarta;
+	register_serial(&req);
+
+	req.iomem_base      = (unsigned char *) &ioc3->sregs.uartb;
+	register_serial(&req);
+}
+
 static int __devinit ioc3_probe(struct pci_dev *pdev,
 	                        const struct pci_device_id *ent)
 {
-	u16 mii0, mii_status, mii2, mii3, mii4;
 	struct net_device *dev = NULL;
 	struct ioc3_private *ip;
 	struct ioc3 *ioc3;
 	unsigned long ioc3_base, ioc3_size;
 	u32 vendor, model, rev;
-	int phy, err;
-
-	dev = init_etherdev(0, sizeof(struct ioc3_private));
+	int err;
 
+	dev = alloc_etherdev(sizeof(struct ioc3_private));
 	if (!dev)
 		return -ENOMEM;
 
+	err = pci_request_regions(pdev, "ioc3");
+	if (err)
+		goto out_free;
+
 	SET_MODULE_OWNER(dev);
 	ip = dev->priv;
-	memset(ip, 0, sizeof(*ip));
-
-	/*
-	 * This probably needs to be register_netdevice, or call
-	 * init_etherdev so that it calls register_netdevice. Quick
-	 * hack for now.
-	 */
-	netif_device_attach(dev);
+	ip->dev = dev;
 
 	dev->irq = pdev->irq;
 
-	ioc3_base = pdev->resource[0].start;
-	ioc3_size = pdev->resource[0].end - ioc3_base;
+	ioc3_base = pci_resource_start(pdev, 0);
+	ioc3_size = pci_resource_len(pdev, 0);
 	ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size);
 	if (!ioc3) {
-		printk(KERN_CRIT"%s: Unable to map device I/O.\n", dev->name);
+		printk(KERN_CRIT "ioc3eth(%s): ioremap failed, goodbye.\n",
+		       pdev->slot_name);
 		err = -ENOMEM;
-		goto out_free;
+		goto out_res;
 	}
 	ip->regs = ioc3;
 
+#ifdef CONFIG_SERIAL
+	ioc3_serial_probe(pdev, ioc3);
+#endif
+
 	spin_lock_init(&ip->ioc3_lock);
 
-	ioc3_stop(dev);
-	ip->emcr = 0;
-	ioc3_init(dev);
-
-	init_timer(&ip->negtimer);
-	ioc3_mii_init(dev, ip, ioc3);
-
-	phy = ip->phy;
-	if (phy == -1) {
-		printk(KERN_CRIT"%s: Didn't find a PHY, goodbye.\n", dev->name);
+	ioc3_stop(ip);
+	ioc3_init(ip);
+
+	init_timer(&ip->ioc3_timer);
+	ioc3_mii_init(ip);
+
+	if (ip->phy == -1) {
+		printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n",
+		       pdev->slot_name);
 		err = -ENODEV;
 		goto out_stop;
 	}
 
-	mii0 = mii_read(ioc3, phy, 0);
-	mii_status = mii_read(ioc3, phy, 1);
-	mii2 = mii_read(ioc3, phy, 2);
-	mii3 = mii_read(ioc3, phy, 3);
-	mii4 = mii_read(ioc3, phy, 4);
-	vendor = (mii2 << 12) | (mii3 >> 4);
-	model  = (mii3 >> 4) & 0x3f;
-	rev    = mii3 & 0xf;
-	printk(KERN_INFO"Using PHY %d, vendor 0x%x, model %d, rev %d.\n",
-	       phy, vendor, model, rev);
-	printk(KERN_INFO "%s:  MII transceiver found at MDIO address "
-	       "%d, config %4.4x status %4.4x.\n",
-	       dev->name, phy, mii0, mii_status);
-
 	ioc3_ssram_disc(ip);
-	printk("IOC3 SSRAM has %d kbyte.\n", ip->emcr & EMCR_BUFSIZ ? 128 : 64);
-
-	ioc3_get_eaddr(dev, ioc3);
+	ioc3_get_eaddr(ip);
 
 	/* The IOC3-specific entries in the device structure. */
 	dev->open		= ioc3_open;
@@ -973,20 +1481,40 @@
 	dev->do_ioctl		= ioc3_ioctl;
 	dev->set_multicast_list	= ioc3_set_multicast_list;
 
+	err = register_netdev(dev);
+	if (err)
+		goto out_stop;
+
+	vendor = (ip->sw_physid1 << 12) | (ip->sw_physid2 >> 4);
+	model  = (ip->sw_physid2 >> 4) & 0x3f;
+	rev    = ip->sw_physid2 & 0xf;
+	printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, "
+	       "rev %d.\n", dev->name, ip->phy, vendor, model, rev);
+	printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name,
+	       ip->emcr & EMCR_BUFSIZ ? 128 : 64);
+
 	return 0;
 
 out_stop:
-	ioc3_stop(dev);
+	ioc3_stop(ip);
 	free_irq(dev->irq, dev);
 	ioc3_free_rings(ip);
+out_res:
+	pci_release_regions(pdev);
 out_free:
 	kfree(dev);
 	return err;
 }
 
-static void __devexit eepro100_remove_one (struct pci_dev *pdev)
+static void __devexit ioc3_remove_one (struct pci_dev *pdev)
 {
-	/* Later ... */
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct ioc3_private *ip = dev->priv;
+	struct ioc3 *ioc3 = ip->regs;
+
+	iounmap(ioc3);
+	/* pci_release_regions(pdev);  Will be used in 2.4.3 */
+	kfree(dev);
 }
 
 static struct pci_device_id ioc3_pci_tbl[] __devinitdata = {
@@ -999,7 +1527,7 @@
 	name:		"ioc3-eth",
 	id_table:	ioc3_pci_tbl,
 	probe:		ioc3_probe,
-	/* remove:		ioc3_remove_one, */
+	remove:		ioc3_remove_one,
 };
 
 static int __init ioc3_init_module(void)
@@ -1080,13 +1608,12 @@
 static void ioc3_timeout(struct net_device *dev)
 {
 	struct ioc3_private *ip = dev->priv;
-	struct ioc3 *ioc3 = ip->regs;
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 
-	ioc3_stop(dev);
-	ioc3_init(dev);
-	ioc3_mii_init(dev, ip, ioc3);
+	ioc3_stop(ip);
+	ioc3_init(ip);
+	ioc3_mii_init(ip);
 
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
@@ -1096,7 +1623,7 @@
  * Given a multicast ethernet address, this routine calculates the
  * address's bit index in the logical address filter mask
  */
-#define CRC_MASK        0xEDB88320
+#define CRC_MASK        0xedb88320
 
 static inline unsigned int
 ioc3_hash(const unsigned char *addr)
@@ -1128,37 +1655,126 @@
 	return temp;
 }
 
-/* Provide ioctl() calls to examine the MII xcvr state. */
+
+/* We provide both the mii-tools and the ethtool ioctls.  */
 static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct ioc3_private *ip = dev->priv;
+	struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data;
 	u16 *data = (u16 *)&rq->ifr_data;
 	struct ioc3 *ioc3 = ip->regs;
-	int phy = ip->phy;
+	struct ethtool_cmd ecmd;
 
 	switch (cmd) {
 	case SIOCGMIIPHY:	/* Get the address of the PHY in use.  */
-		if (phy == -1)
+		if (ip->phy == -1)
 			return -ENODEV;
-		data[0] = phy;
+		data[0] = ip->phy;
 		return 0;
 
-	case SIOCGMIIREG:	/* Read any PHY register.  */
+	case SIOCGMIIREG: {	/* Read a PHY register.  */
+		unsigned int phy = data[0];
+		unsigned int reg = data[1];
+
+		if (phy > 0x1f || reg > 0x1f)
+			return -EINVAL;
+
 		spin_lock_irq(&ip->ioc3_lock);
-		data[3] = mii_read(ioc3, data[0], data[1]);
+		while (ioc3->micr & MICR_BUSY);
+		ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG;
+		while (ioc3->micr & MICR_BUSY);
+		data[3] = (ioc3->midr_r & MIDR_DATA_MASK);
 		spin_unlock_irq(&ip->ioc3_lock);
+
 		return 0;
 
-	case SIOCSMIIREG:	/* Write any PHY register.  */
+	case SIOCSMIIREG:	/* Write a PHY register.  */
+		phy = data[0];
+		reg = data[1];
+
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
+
+		if (phy > 0x1f || reg > 0x1f)
+			return -EINVAL;
+
 		spin_lock_irq(&ip->ioc3_lock);
-		mii_write(ioc3, data[0], data[1], data[2]);
+		while (ioc3->micr & MICR_BUSY);
+		ioc3->midr_w = data[2];
+		ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg;
+		while (ioc3->micr & MICR_BUSY);
 		spin_unlock_irq(&ip->ioc3_lock);
+
 		return 0;
+		}
+	case SIOCETHTOOL:
+		if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
+			return -EFAULT;
+
+		if (ecmd.cmd == ETHTOOL_GSET) {
+			ecmd.supported =
+				(SUPPORTED_10baseT_Half |
+				 SUPPORTED_10baseT_Full |
+				 SUPPORTED_100baseT_Half |
+				 SUPPORTED_100baseT_Full | SUPPORTED_Autoneg |
+				 SUPPORTED_TP | SUPPORTED_MII);
+
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_INTERNAL;
+			ecmd.phy_address = ip->phy;
+
+			/* Record PHY settings. */
+			spin_lock_irq(&ip->ioc3_lock);
+			ip->sw_bmcr = mii_read(ip, MII_BMCR);
+			ip->sw_lpa = mii_read(ip, MII_LPA);
+			spin_unlock_irq(&ip->ioc3_lock);
+			if (ip->sw_bmcr & BMCR_ANENABLE) {
+				ecmd.autoneg = AUTONEG_ENABLE;
+				ecmd.speed = (ip->sw_lpa &
+			             (LPA_100HALF | LPA_100FULL)) ?
+			             SPEED_100 : SPEED_10;
+			if (ecmd.speed == SPEED_100)
+				ecmd.duplex = (ip->sw_lpa & (LPA_100FULL)) ?
+				              DUPLEX_FULL : DUPLEX_HALF;
+			else
+				ecmd.duplex = (ip->sw_lpa & (LPA_10FULL)) ?
+				              DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				ecmd.autoneg = AUTONEG_DISABLE;
+				ecmd.speed = (ip->sw_bmcr & BMCR_SPEED100) ?
+				             SPEED_100 : SPEED_10;
+				ecmd.duplex = (ip->sw_bmcr & BMCR_FULLDPLX) ?
+				              DUPLEX_FULL : DUPLEX_HALF;
+			}
+			if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
+		} else if (ecmd.cmd == ETHTOOL_SSET) {
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+
+			/* Verify the settings we care about. */
+			if (ecmd.autoneg != AUTONEG_ENABLE &&
+			    ecmd.autoneg != AUTONEG_DISABLE)
+				return -EINVAL;
+
+			if (ecmd.autoneg == AUTONEG_DISABLE &&
+			    ((ecmd.speed != SPEED_100 &&
+			      ecmd.speed != SPEED_10) ||
+			     (ecmd.duplex != DUPLEX_HALF &&
+			      ecmd.duplex != DUPLEX_FULL)))
+				return -EINVAL;
+
+			/* Ok, do it to it. */
+			del_timer(&ip->ioc3_timer);
+			spin_lock_irq(&ip->ioc3_lock);
+			ioc3_start_auto_negotiation(ip, &ecmd);
+			spin_unlock_irq(&ip->ioc3_lock);
 
-	default:
-		return -EOPNOTSUPP;
+			return 0;
+		} else
+		default:
+			return -EOPNOTSUPP;
 	}
 
 	return -EOPNOTSUPP;
@@ -1169,10 +1785,11 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	struct ioc3_private *ip = dev->priv;
 	struct ioc3 *ioc3 = ip->regs;
-	char *addr = dmi->dmi_addr;
 	u64 ehar = 0;
 	int i;
 
+	netif_stop_queue(dev);				/* Lock out others. */
+
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous.  */
 		/* Unconditionally log net taps.  */
 		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
@@ -1192,6 +1809,7 @@
 			ip->ehar_l = 0xffffffff;
 		} else {
 			for (i = 0; i < dev->mc_count; i++) {
+				char *addr = dmi->dmi_addr;
 				dmi = dmi->next;
 
 				if (!(*addr & 1))
@@ -1205,6 +1823,8 @@
 		ioc3->ehar_h = ip->ehar_h;
 		ioc3->ehar_l = ip->ehar_l;
 	}
+
+	netif_wake_queue(dev);			/* Let us get going again. */
 }
 
 MODULE_AUTHOR("Ralf Baechle <ralf@oss.sgi.com>");
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in
--- v2.4.6/linux/drivers/net/irda/Config.in	Tue May  1 16:05:00 2001
+++ linux/drivers/net/irda/Config.in	Wed Jul  4 11:50:38 2001
@@ -23,6 +23,7 @@
 dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
+dep_tristate 'ALi M5123 FIR (Experimental)' CONFIG_ALI_FIR $CONFIG_IRDA
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile
--- v2.4.6/linux/drivers/net/irda/Makefile	Tue May  1 16:05:00 2001
+++ linux/drivers/net/irda/Makefile	Wed Jul  4 11:50:38 2001
@@ -17,6 +17,7 @@
 obj-$(CONFIG_WINBOND_FIR)	+= w83977af_ir.o
 obj-$(CONFIG_TOSHIBA_FIR)	+= toshoboe.o
 obj-$(CONFIG_SMC_IRCC_FIR)	+= smc-ircc.o	irport.o
+obj-$(CONFIG_ALI_FIR)		+= ali-ircc.o
 obj-$(CONFIG_ESI_DONGLE)	+= esi.o
 obj-$(CONFIG_TEKRAM_DONGLE)	+= tekram.o
 obj-$(CONFIG_ACTISYS_DONGLE)	+= actisys.o
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- v2.4.6/linux/drivers/net/irda/ali-ircc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/ali-ircc.c	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,2306 @@
+/*********************************************************************
+ *                
+ * Filename:      ali-ircc.h
+ * Version:       0.5
+ * Description:   Driver for the ALI M1535D and M1543C FIR Controller
+ * Status:        Experimental.
+ * Author:        Benjamin Kong <benjamin_kong@ali.com.tw>
+ * Created at:    2000/10/16 03:46PM
+ * Modified at:   2001/1/3 02:55PM
+ * Modified by:   Benjamin Kong <benjamin_kong@ali.com.tw>
+ * 
+ *     Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw>
+ *     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; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ ********************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/rtnetlink.h>
+#include <linux/serial_reg.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include <linux/pm.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+
+#include <net/irda/ali-ircc.h>
+
+#define CHIP_IO_EXTENT 8
+#define BROKEN_DONGLE_ID
+
+static char *driver_name = "ali-ircc";
+
+/* Module parameters */
+static int qos_mtt_bits = 0x07;  /* 1 ms or more */
+
+/* Use BIOS settions by default, but user may supply module parameters */
+static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0 };
+static unsigned int dma[] = { 0, 0, 0, 0 };
+
+static int  ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info);
+static int  ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);
+static int  ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);
+static int  ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);
+
+/* These are the currently known ALi sourth-bridge chipsets, the only one difference
+ * is that M1543C doesn't support HP HDSL-3600
+ */
+static ali_chip_t chips[] =
+{
+	{ "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 },
+	{ "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 },
+	{ NULL }
+};
+
+/* Max 4 instances for now */
+static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
+
+/* Dongle Types */
+static char *dongle_types[] = {
+	"TFDS6000",
+	"HP HSDL-3600",
+	"HP HSDL-1100",	
+	"No dongle connected",
+};
+
+/* Some prototypes */
+static int  ali_ircc_open(int i, chipio_t *info);
+
+#ifdef MODULE
+static int  ali_ircc_close(struct ali_ircc_cb *self);
+#endif /* MODULE */
+
+static int  ali_ircc_setup(chipio_t *info);
+static int  ali_ircc_is_receiving(struct ali_ircc_cb *self);
+static int  ali_ircc_net_init(struct net_device *dev);
+static int  ali_ircc_net_open(struct net_device *dev);
+static int  ali_ircc_net_close(struct net_device *dev);
+static int  ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int  ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud);
+static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void ali_ircc_suspend(struct ali_ircc_cb *self);
+static void ali_ircc_wakeup(struct ali_ircc_cb *self);
+static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev);
+
+/* SIR function */
+static int  ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+static void ali_ircc_sir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs);
+static void ali_ircc_sir_receive(struct ali_ircc_cb *self);
+static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self);
+static int  ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);
+static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed);
+
+/* FIR function */
+static int  ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed);
+static void ali_ircc_fir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs);
+static int  ali_ircc_dma_receive(struct ali_ircc_cb *self); 
+static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self);
+static int  ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self);
+static void ali_ircc_dma_xmit(struct ali_ircc_cb *self);
+
+/* My Function */
+static int  ali_ircc_read_dongle_id (int i, chipio_t *info);
+static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed);
+
+/* ALi chip function */
+static void SIR2FIR(int iobase);
+static void FIR2SIR(int iobase);
+static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable);
+
+/*
+ * Function ali_ircc_init ()
+ *
+ *    Initialize chip. Find out whay kinds of chips we are dealing with
+ *    and their configuation registers address
+ */
+int __init ali_ircc_init(void)
+{
+	ali_chip_t *chip;
+	chipio_t info;
+	int ret = -ENODEV;
+	int cfg, cfg_base;
+	int reg, revision;
+	int i = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	/* Probe for all the ALi chipsets we know about */
+	for (chip= chips; chip->name; chip++, i++) 
+	{
+		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", chip->name);
+				
+		/* Try all config registers for this chip */
+		for (cfg=0; cfg<2; cfg++)
+		{
+			cfg_base = chip->cfg[cfg];
+			if (!cfg_base)
+				continue;
+				
+			memset(&info, 0, sizeof(chipio_t));
+			info.cfg_base = cfg_base;
+			info.fir_base = io[i];
+			info.dma = dma[i];
+			info.irq = irq[i];
+			
+			
+			/* Enter Configuration */
+			outb(chip->entr1, cfg_base);
+			outb(chip->entr2, cfg_base);
+			
+			/* Select Logical Device 5 Registers (UART2) */
+			outb(0x07, cfg_base);
+			outb(0x05, cfg_base+1);
+			
+			/* Read Chip Identification Register */
+			outb(chip->cid_index, cfg_base);	
+			reg = inb(cfg_base+1);	
+				
+			if (reg == chip->cid_value)
+			{
+				IRDA_DEBUG(2, __FUNCTION__
+					"(), Chip found at 0x%03x\n", cfg_base);
+					   
+				outb(0x1F, cfg_base);
+				revision = inb(cfg_base+1);
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "(), Found %s chip, revision=%d\n",
+					   chip->name, revision);					
+				
+				/* 
+				 * If the user supplies the base address, then
+				 * we init the chip, if not we probe the values
+				 * set by the BIOS
+				 */				
+				if (io[i] < 2000)
+				{
+					chip->init(chip, &info);
+				}
+				else
+				{
+					chip->probe(chip, &info);	
+				}
+				
+				if (ali_ircc_open(i, &info) == 0)
+					ret = 0;
+				i++;				
+			}
+			else
+			{
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "(), No %s chip at 0x%03x\n", chip->name, cfg_base);
+			}
+			/* Exit configuration */
+			outb(0xbb, cfg_base);
+		}
+	}		
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");					   		
+	return ret;
+}
+
+/*
+ * Function ali_ircc_cleanup ()
+ *
+ *    Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void ali_ircc_cleanup(void)
+{
+	int i;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	
+	pm_unregister_all(ali_ircc_pmproc);
+
+	for (i=0; i < 4; i++) {
+		if (dev_self[i])
+			ali_ircc_close(dev_self[i]);
+	}
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+}
+#endif /* MODULE */
+
+/*
+ * Function ali_ircc_open (int i, chipio_t *inf)
+ *
+ *    Open driver instance
+ *
+ */
+static int ali_ircc_open(int i, chipio_t *info)
+{
+	struct net_device *dev;
+	struct ali_ircc_cb *self;
+	struct pm_dev *pmdev;
+	int dongle_id;
+	int ret;
+	int err;
+			
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	
+	/* Set FIR FIFO and DMA Threshold */
+	if ((ali_ircc_setup(info)) == -1)
+		return -1;
+		
+	/* Allocate new instance of the driver */
+	self = kmalloc(sizeof(struct ali_ircc_cb), GFP_KERNEL);
+	if (self == NULL) 
+	{
+		ERROR(__FUNCTION__ "(), can't allocate memory for control block!\n");
+		return -ENOMEM;
+	}
+	memset(self, 0, sizeof(struct ali_ircc_cb));
+	spin_lock_init(&self->lock);
+   
+	/* Need to store self somewhere */
+	dev_self[i] = self;
+	self->index = i;
+
+	/* Initialize IO */
+	self->io.cfg_base  = info->cfg_base;	/* In ali_ircc_probe_53 assign 		*/
+	self->io.fir_base  = info->fir_base;	/* info->sir_base = info->fir_base 	*/
+	self->io.sir_base  = info->sir_base; 	/* ALi SIR and FIR use the same address */
+        self->io.irq       = info->irq;
+        self->io.fir_ext   = CHIP_IO_EXTENT;
+        self->io.dma       = info->dma;
+        self->io.fifo_size = 16;		/* SIR: 16, FIR: 32 Benjamin 2000/11/1 */
+	
+	/* Reserve the ioports that we need */
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
+	if (ret < 0) { 
+		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
+			self->io.fir_base);
+		dev_self[i] = NULL;
+		kfree(self);
+		return -ENODEV;
+	}
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&self->qos);
+	
+	/* The only value we must override it the baudrate */
+	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM
+			
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+			
+	irda_qos_bits_to_value(&self->qos);
+	
+	self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; 	// benjamin 2000/11/8 05:27PM	
+
+	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+	self->rx_buff.truesize = 14384; 
+	self->tx_buff.truesize = 14384;
+
+	/* Allocate memory if needed */
+	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL |GFP_DMA); 
+	if (self->rx_buff.head == NULL) 
+	{
+		kfree(self);
+		return -ENOMEM;
+	}
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	
+	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA); 
+	if (self->tx_buff.head == NULL) {
+		kfree(self);
+		kfree(self->rx_buff.head);
+		return -ENOMEM;
+	}
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Tx queue info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -ENOMEM;
+	}
+
+	dev->priv = (void *) self;
+	self->netdev = dev;
+	
+	/* Override the network functions we need to use */
+	dev->init            = ali_ircc_net_init;
+	dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
+	dev->open            = ali_ircc_net_open;
+	dev->stop            = ali_ircc_net_close;
+	dev->do_ioctl        = ali_ircc_net_ioctl;
+	dev->get_stats	     = ali_ircc_net_get_stats;
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+	/* Check dongle id */
+	dongle_id = ali_ircc_read_dongle_id(i, info);
+	MESSAGE(__FUNCTION__ "(), %s, Found dongle: %s\n", driver_name, dongle_types[dongle_id]);
+		
+	self->io.dongle_id = dongle_id;
+	
+        pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ali_ircc_pmproc);
+        if (pmdev)
+                pmdev->data = self;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	
+	return 0;
+}
+
+
+#ifdef MODULE
+/*
+ * Function ali_ircc_close (self)
+ *
+ *    Close driver instance
+ *
+ */
+static int ali_ircc_close(struct ali_ircc_cb *self)
+{
+	int iobase;
+
+	IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n");
+
+	ASSERT(self != NULL, return -1;);
+
+        iobase = self->io.fir_base;
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+	}
+
+	/* Release the PORT that this driver is using */
+	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", self->io.fir_base);
+	release_region(self->io.fir_base, self->io.fir_ext);
+
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+
+	dev_self[self->index] = NULL;
+	kfree(self);
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	
+	return 0;
+}
+#endif /* MODULE */
+
+/*
+ * Function ali_ircc_init_43 (chip, info)
+ *
+ *    Initialize the ALi M1543 chip. 
+ */
+static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info) 
+{
+	/* All controller information like I/O address, DMA channel, IRQ
+	 * are set by BIOS
+	 */
+	
+	return 0;
+}
+
+/*
+ * Function ali_ircc_init_53 (chip, info)
+ *
+ *    Initialize the ALi M1535 chip. 
+ */
+static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info) 
+{
+	/* All controller information like I/O address, DMA channel, IRQ
+	 * are set by BIOS
+	 */
+	
+	return 0;
+}
+
+/*
+ * Function ali_ircc_probe_43 (chip, info)
+ *    	
+ *	Probes for the ALi M1543
+ */
+static int ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info)
+{
+	return 0;	
+}
+
+/*
+ * Function ali_ircc_probe_53 (chip, info)
+ *    	
+ *	Probes for the ALi M1535D or M1535
+ */
+static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info)
+{
+	int cfg_base = info->cfg_base;
+	int hi, low, reg;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	/* Enter Configuration */
+	outb(chip->entr1, cfg_base);
+	outb(chip->entr2, cfg_base);
+	
+	/* Select Logical Device 5 Registers (UART2) */
+	outb(0x07, cfg_base);
+	outb(0x05, cfg_base+1);
+	
+	/* Read address control register */
+	outb(0x60, cfg_base);
+	hi = inb(cfg_base+1);	
+	outb(0x61, cfg_base);
+	low = inb(cfg_base+1);
+	info->fir_base = (hi<<8) + low;
+	
+	info->sir_base = info->fir_base;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", info->fir_base);
+		
+	/* Read IRQ control register */
+	outb(0x70, cfg_base);
+	reg = inb(cfg_base+1);
+	info->irq = reg & 0x0f;
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+	
+	/* Read DMA channel */
+	outb(0x74, cfg_base);
+	reg = inb(cfg_base+1);
+	info->dma = reg & 0x07;
+	
+	if(info->dma == 0x04)
+		WARNING(__FUNCTION__ "(), No DMA channel assigned !\n");
+	else
+		IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+	
+	/* Read Enabled Status */
+	outb(0x30, cfg_base);
+	reg = inb(cfg_base+1);
+	info->enabled = (reg & 0x80) && (reg & 0x01);
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing enabled=%d\n", info->enabled);
+	
+	/* Read Power Status */
+	outb(0x22, cfg_base);
+	reg = inb(cfg_base+1);
+	info->suspended = (reg & 0x20);
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing suspended=%d\n", info->suspended);
+	
+	/* Exit configuration */
+	outb(0xbb, cfg_base);
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");	
+	
+	return 0;	
+}
+
+/*
+ * Function ali_ircc_setup (info)
+ *
+ *    	Set FIR FIFO and DMA Threshold
+ *	Returns non-negative on success.
+ *
+ */
+static int ali_ircc_setup(chipio_t *info)
+{
+	unsigned char tmp;
+	int version;
+	int iobase = info->fir_base;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	/* Switch to FIR space */
+	SIR2FIR(iobase);
+	
+	/* Master Reset */
+	outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM
+	
+	/* Read FIR ID Version Register */
+	switch_bank(iobase, BANK3);
+	version = inb(iobase+FIR_ID_VR);
+	
+	/* Should be 0x00 in the M1535/M1535D */
+	if(version != 0x00)
+	{
+		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+		return -1;
+	}
+	
+	// MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base);
+	
+	/* Set FIR FIFO Threshold Register */
+	switch_bank(iobase, BANK1);
+	outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR);
+	
+	/* Set FIR DMA Threshold Register */
+	outb(RX_DMA_Threshold, iobase+FIR_DMA_TR);
+	
+	/* CRC enable */
+	switch_bank(iobase, BANK2);
+	outb(inb(iobase+FIR_IRDA_CR) | IRDA_CR_CRC, iobase+FIR_IRDA_CR);
+	
+	/* NDIS driver set TX Length here BANK2 Alias 3, Alias4*/
+	
+	/* Switch to Bank 0 */
+	switch_bank(iobase, BANK0);
+	
+	tmp = inb(iobase+FIR_LCR_B);
+	tmp &=~0x20; // disable SIP
+	tmp |= 0x80; // these two steps make RX mode
+	tmp &= 0xbf;	
+	outb(tmp, iobase+FIR_LCR_B);
+		
+	/* Disable Interrupt */
+	outb(0x00, iobase+FIR_IER);
+	
+	
+	/* Switch to SIR space */
+	FIR2SIR(iobase);
+	
+	MESSAGE("%s, driver loaded (Benjamin Kong)\n", driver_name);
+	
+	/* Enable receive interrupts */ 
+	// outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
+	// Turn on the interrupts in ali_ircc_net_open
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return 0;
+}
+
+/*
+ * Function ali_ircc_read_dongle_id (int index, info)
+ *
+ * Try to read dongle indentification. This procedure needs to be executed
+ * once after power-on/reset. It also needs to be used whenever you suspect
+ * that the user may have plugged/unplugged the IrDA Dongle.
+ */
+static int ali_ircc_read_dongle_id (int i, chipio_t *info)
+{
+	int dongle_id, reg;
+	int cfg_base = info->cfg_base;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+		
+	/* Enter Configuration */
+	outb(chips[i].entr1, cfg_base);
+	outb(chips[i].entr2, cfg_base);
+	
+	/* Select Logical Device 5 Registers (UART2) */
+	outb(0x07, cfg_base);
+	outb(0x05, cfg_base+1);
+	
+	/* Read Dongle ID */
+	outb(0xf0, cfg_base);
+	reg = inb(cfg_base+1);	
+	dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01);
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing dongle_id=%d, dongle_types=%s\n", 
+		dongle_id, dongle_types[dongle_id]);
+	
+	/* Exit configuration */
+	outb(0xbb, cfg_base);
+			
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return dongle_id;
+}
+
+/*
+ * Function ali_ircc_interrupt (irq, dev_id, regs)
+ *
+ *    An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct ali_ircc_cb *self;
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+		
+ 	if (!dev) {
+		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
+		return;
+	}	
+	
+	self = (struct ali_ircc_cb *) dev->priv;
+	
+	spin_lock(&self->lock);
+	
+	/* Dispatch interrupt handler for the current speed */
+	if (self->io.speed > 115200)
+		ali_ircc_fir_interrupt(irq, self, regs);
+	else
+		ali_ircc_sir_interrupt(irq, self, regs);	
+		
+	spin_unlock(&self->lock);
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");		
+}
+/*
+ * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self, regs)
+ *
+ *    Handle MIR/FIR interrupt
+ *
+ */
+static void ali_ircc_fir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs)
+{
+	__u8 eir, OldMessageCount;
+	int iobase, tmp;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	iobase = self->io.fir_base;
+	
+	switch_bank(iobase, BANK0);	
+	self->InterruptID = inb(iobase+FIR_IIR);		
+	self->BusStatus = inb(iobase+FIR_BSR);	
+	
+	OldMessageCount = (self->LineStatus + 1) & 0x07;
+	self->LineStatus = inb(iobase+FIR_LSR);	
+	//self->ier = inb(iobase+FIR_IER); 		2000/12/1 04:32PM
+	eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ 
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), self->InterruptID = %x\n",self->InterruptID);
+	IRDA_DEBUG(1, __FUNCTION__ "(), self->LineStatus = %x\n",self->LineStatus);
+	IRDA_DEBUG(1, __FUNCTION__ "(), self->ier = %x\n",self->ier);
+	IRDA_DEBUG(1, __FUNCTION__ "(), eir = %x\n",eir);
+	
+	/* Disable interrupts */
+	 SetCOMInterrupts(self, FALSE);
+	
+	/* Tx or Rx Interrupt */
+	
+	if (eir & IIR_EOM) 
+	{		
+		if (self->io.direction == IO_XMIT) /* TX */
+		{
+			IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Tx) *******\n");
+			
+			if(ali_ircc_dma_xmit_complete(self))
+			{
+				if (irda_device_txqueue_empty(self->netdev)) 
+				{
+					/* Prepare for receive */
+					ali_ircc_dma_receive(self);					
+					self->ier = IER_EOM;									
+				}
+			}
+			else
+			{
+				self->ier = IER_EOM; 					
+			}
+									
+		}	
+		else /* RX */
+		{
+			IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Rx) *******\n");
+			
+			if(OldMessageCount > ((self->LineStatus+1) & 0x07))
+			{
+				self->rcvFramesOverflow = TRUE;	
+				IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******** \n");
+			}
+						
+			if (ali_ircc_dma_receive_complete(self))
+			{
+				IRDA_DEBUG(1, __FUNCTION__ "(), ******* receive complete ******** \n");
+				
+				self->ier = IER_EOM;				
+			}
+			else
+			{
+				IRDA_DEBUG(1, __FUNCTION__ "(), ******* Not receive complete ******** \n");
+				
+				self->ier = IER_EOM | IER_TIMER;								
+			}	
+		
+		}		
+	}
+	/* Timer Interrupt */
+	else if (eir & IIR_TIMER)
+	{	
+		if(OldMessageCount > ((self->LineStatus+1) & 0x07))
+		{
+			self->rcvFramesOverflow = TRUE;	
+			IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******* \n");
+		}
+		/* Disable Timer */
+		switch_bank(iobase, BANK1);
+		tmp = inb(iobase+FIR_CR);
+		outb( tmp& ~CR_TIMER_EN, iobase+FIR_CR);
+		
+		/* Check if this is a Tx timer interrupt */
+		if (self->io.direction == IO_XMIT)
+		{
+			ali_ircc_dma_xmit(self);
+			
+			/* Interrupt on EOM */
+			self->ier = IER_EOM;
+									
+		}
+		else /* Rx */
+		{
+			if(ali_ircc_dma_receive_complete(self)) 
+			{
+				self->ier = IER_EOM;
+			}
+			else
+			{
+				self->ier = IER_EOM | IER_TIMER;
+			}	
+		}		
+	}
+	
+	/* Restore Interrupt */	
+	SetCOMInterrupts(self, TRUE);	
+		
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ---------------\n");
+}
+
+/*
+ * Function ali_ircc_sir_interrupt (irq, self, eir)
+ *
+ *    Handle SIR interrupt
+ *
+ */
+static void ali_ircc_sir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs)
+{
+	int iobase;
+	int iir, lsr;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	iobase = self->io.sir_base;
+
+	iir = inb(iobase+UART_IIR) & UART_IIR_ID;
+	if (iir) {	
+		/* Clear interrupt */
+		lsr = inb(iobase+UART_LSR);
+
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+			   iir, lsr, iobase);
+
+		switch (iir) 
+		{
+			case UART_IIR_RLSI:
+				IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
+				break;
+			case UART_IIR_RDI:
+				/* Receive interrupt */
+				ali_ircc_sir_receive(self);
+				break;
+			case UART_IIR_THRI:
+				if (lsr & UART_LSR_THRE)
+				{
+					/* Transmitter ready for data */
+					ali_ircc_sir_write_wakeup(self);				
+				}				
+				break;
+			default:
+				IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+				break;
+		} 
+		
+	}
+	
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+
+/*
+ * Function ali_ircc_sir_receive (self)
+ *
+ *    Receive one frame from the infrared port
+ *
+ */
+static void ali_ircc_sir_receive(struct ali_ircc_cb *self) 
+{
+	int boguscount = 0;
+	int iobase;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	ASSERT(self != NULL, return;);
+
+	iobase = self->io.sir_base;
+
+	/*  
+	 * Receive all characters in Rx FIFO, unwrap and unstuff them. 
+         * async_unwrap_char will deliver all found frames  
+	 */
+	do {
+		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
+				  inb(iobase+UART_RX));
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 32) {
+			IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
+			break;
+		}
+	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+/*
+ * Function ali_ircc_sir_write_wakeup (tty)
+ *
+ *    Called by the driver when there's room for more data.  If we have
+ *    more packets to send, we send them here.
+ *
+ */
+static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self)
+{
+	int actual = 0;
+	int iobase;	
+
+	ASSERT(self != NULL, return;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	iobase = self->io.sir_base;
+
+	/* Finished with frame?  */
+	if (self->tx_buff.len > 0)  
+	{
+		/* Write data left in transmit buffer */
+		actual = ali_ircc_sir_write(iobase, self->io.fifo_size, 
+				      self->tx_buff.data, self->tx_buff.len);
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
+	} 
+	else 
+	{
+		if (self->new_speed) 
+		{
+			/* We must wait until all data are gone */
+			while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT))
+				IRDA_DEBUG(1, __FUNCTION__ "(), UART_LSR_THRE\n");
+			
+			IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed! self->new_speed = %d\n", self->new_speed);
+			ali_ircc_change_speed(self, self->new_speed);
+			self->new_speed = 0;			
+			
+			// benjamin 2000/11/10 06:32PM
+			if (self->io.speed > 115200)
+			{
+				IRDA_DEBUG(2, __FUNCTION__ "(), ali_ircc_change_speed from UART_LSR_TEMT \n");				
+					
+				self->ier = IER_EOM;
+				// SetCOMInterrupts(self, TRUE);							
+				return;							
+			}
+		}
+		else
+		{
+			netif_wake_queue(self->netdev);	
+		}
+			
+		self->stats.tx_packets++;
+		
+		/* Turn on receive interrupts */
+		outb(UART_IER_RDI, iobase+UART_IER);
+	}
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
+{
+	struct net_device *dev = self->netdev;
+	int iobase;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), setting speed = %d \n", baud);
+	
+	iobase = self->io.fir_base;
+	
+	SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM
+	
+	/* Go to MIR, FIR Speed */
+	if (baud > 115200)
+	{
+		
+					
+		ali_ircc_fir_change_speed(self, baud);			
+		
+		/* Install FIR xmit handler*/
+		dev->hard_start_xmit = ali_ircc_fir_hard_xmit;		
+				
+		/* Enable Interuupt */
+		self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM					
+				
+		/* Be ready for incomming frames */
+		ali_ircc_dma_receive(self);	// benajmin 2000/11/8 07:46PM not complete
+	}	
+	/* Go to SIR Speed */
+	else
+	{
+		ali_ircc_sir_change_speed(self, baud);
+				
+		/* Install SIR xmit handler*/
+		dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
+	}
+	
+		
+	SetCOMInterrupts(self, TRUE);	// 2000/11/24 11:43AM
+		
+	netif_wake_queue(self->netdev);	
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
+{
+		
+	int iobase; 
+	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
+	struct net_device *dev;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+		
+	ASSERT(self != NULL, return;);
+
+	dev = self->netdev;
+	iobase = self->io.fir_base;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), self->io.speed = %d, change to speed = %d\n",self->io.speed,baud);
+	
+	/* Come from SIR speed */
+	if(self->io.speed <=115200)
+	{
+		SIR2FIR(iobase);
+	}
+		
+	/* Update accounting for new speed */
+	self->io.speed = baud;
+		
+	// Set Dongle Speed mode
+	ali_ircc_change_dongle_speed(self, baud);
+		
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+/*
+ * Function ali_sir_change_speed (self, speed)
+ *
+ *    Set speed of IrDA port to specified baudrate
+ *
+ */
+static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
+{
+	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
+	unsigned long flags;
+	int iobase; 
+	int fcr;    /* FIFO control reg */
+	int lcr;    /* Line control reg */
+	int divisor;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+
+	ASSERT(self != NULL, return;);
+
+	iobase = self->io.sir_base;
+	
+	/* Come from MIR or FIR speed */
+	if(self->io.speed >115200)
+	{	
+		// Set Dongle Speed mode first
+		ali_ircc_change_dongle_speed(self, speed);
+			
+		FIR2SIR(iobase);
+	}
+		
+	// Clear Line and Auxiluary status registers 2000/11/24 11:47AM
+		
+	inb(iobase+UART_LSR);
+	inb(iobase+UART_SCR);
+		
+	/* Update accounting for new speed */
+	self->io.speed = speed;
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	divisor = 115200/speed;
+	
+	fcr = UART_FCR_ENABLE_FIFO;
+
+	/* 
+	 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+	 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+	 * about this timeout since it will always be fast enough. 
+	 */
+	if (self->io.speed < 38400)
+		fcr |= UART_FCR_TRIGGER_1;
+	else 
+		fcr |= UART_FCR_TRIGGER_14;
+        
+	/* IrDA ports use 8N1 */
+	lcr = UART_LCR_WLEN8;
+	
+	outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
+	outb(divisor & 0xff,      iobase+UART_DLL); /* Set speed */
+	outb(divisor >> 8,	  iobase+UART_DLM);
+	outb(lcr,		  iobase+UART_LCR); /* Set 8N1	*/
+	outb(fcr,		  iobase+UART_FCR); /* Enable FIFO's */
+
+	/* without this, the conection will be broken after come back from FIR speed,
+	   but with this, the SIR connection is harder to established */
+	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
+	
+	spin_unlock_irqrestore(&self->lock, flags);
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
+{
+	
+	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
+	int iobase,dongle_id;
+	unsigned long flags;
+	int tmp = 0;
+			
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	
+	iobase = self->io.fir_base; 	/* or iobase = self->io.sir_base; */
+	dongle_id = self->io.dongle_id;
+	
+	save_flags(flags);
+	cli();
+		
+	IRDA_DEBUG(1, __FUNCTION__ "(), Set Speed for %s , Speed = %d\n", dongle_types[dongle_id], speed);		
+	
+	switch_bank(iobase, BANK2);
+	tmp = inb(iobase+FIR_IRDA_CR);
+		
+	/* IBM type dongle */
+	if(dongle_id == 0)
+	{				
+		if(speed == 4000000)
+		{
+			//	      __ __	
+			// SD/MODE __|     |__ __
+			//               __ __ 
+			// IRTX    __ __|     |__
+			//         T1 T2 T3 T4 T5
+			
+			tmp &=  ~IRDA_CR_HDLC;		// HDLC=0
+			tmp |= IRDA_CR_CRC;	   	// CRC=1
+			
+			switch_bank(iobase, BANK2);
+			outb(tmp, iobase+FIR_IRDA_CR);
+			
+      			// T1 -> SD/MODE:0 IRTX:0
+      			tmp &= ~0x09;
+      			tmp |= 0x02;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// T2 -> SD/MODE:1 IRTX:0
+      			tmp &= ~0x01;
+      			tmp |= 0x0a;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// T3 -> SD/MODE:1 IRTX:1
+      			tmp |= 0x0b;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// T4 -> SD/MODE:0 IRTX:1
+      			tmp &= ~0x08;
+      			tmp |= 0x03;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// T5 -> SD/MODE:0 IRTX:0
+      			tmp &= ~0x09;
+      			tmp |= 0x02;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// reset -> Normal TX output Signal
+      			outb(tmp & ~0x02, iobase+FIR_IRDA_CR);      			
+		}
+		else /* speed <=1152000 */
+		{	
+			//	      __	
+			// SD/MODE __|  |__
+			//
+			// IRTX    ________
+			//         T1 T2 T3  
+			
+			/* MIR 115200, 57600 */
+			if (speed==1152000)
+			{
+				tmp |= 0xA0;	   //HDLC=1, 1.152Mbps=1
+      			}
+      			else
+      			{
+				tmp &=~0x80;	   //HDLC 0.576Mbps
+				tmp |= 0x20;	   //HDLC=1,
+      			}			
+      			
+      			tmp |= IRDA_CR_CRC;	   	// CRC=1
+      			
+      			switch_bank(iobase, BANK2);
+      			outb(tmp, iobase+FIR_IRDA_CR);
+						
+			/* MIR 115200, 57600 */	
+						
+			//switch_bank(iobase, BANK2);			
+			// T1 -> SD/MODE:0 IRTX:0
+      			tmp &= ~0x09;
+      			tmp |= 0x02;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// T2 -> SD/MODE:1 IRTX:0
+      			tmp &= ~0x01;     
+      			tmp |= 0x0a;      
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			
+      			// T3 -> SD/MODE:0 IRTX:0
+      			tmp &= ~0x09;
+      			tmp |= 0x02;
+      			outb(tmp, iobase+FIR_IRDA_CR);
+      			udelay(2);
+      			
+      			// reset -> Normal TX output Signal
+      			outb(tmp & ~0x02, iobase+FIR_IRDA_CR);      						
+		}		
+	}
+	else if (dongle_id == 1) /* HP HDSL-3600 */
+	{
+		switch(speed)
+		{
+		case 4000000:
+			tmp &=  ~IRDA_CR_HDLC;	// HDLC=0
+			break;	
+			
+		case 1152000:
+			tmp |= 0xA0;	   	// HDLC=1, 1.152Mbps=1
+      			break;
+      			
+      		case 576000:
+      			tmp &=~0x80;	   	// HDLC 0.576Mbps
+			tmp |= 0x20;	   	// HDLC=1,
+			break;
+      		}			
+			
+		tmp |= IRDA_CR_CRC;	   	// CRC=1
+			
+		switch_bank(iobase, BANK2);
+      		outb(tmp, iobase+FIR_IRDA_CR);		
+	}
+	else /* HP HDSL-1100 */
+	{
+		if(speed <= 115200) /* SIR */
+		{
+			
+			tmp &= ~IRDA_CR_FIR_SIN;	// HP sin select = 0
+			
+			switch_bank(iobase, BANK2);
+      			outb(tmp, iobase+FIR_IRDA_CR);			
+		}
+		else /* MIR FIR */
+		{	
+			
+			switch(speed)
+			{
+			case 4000000:
+				tmp &=  ~IRDA_CR_HDLC;	// HDLC=0
+				break;	
+			
+			case 1152000:
+				tmp |= 0xA0;	   	// HDLC=1, 1.152Mbps=1
+      				break;
+      			
+      			case 576000:
+      				tmp &=~0x80;	   	// HDLC 0.576Mbps
+				tmp |= 0x20;	   	// HDLC=1,
+				break;
+      			}			
+			
+			tmp |= IRDA_CR_CRC;	   	// CRC=1
+			tmp |= IRDA_CR_FIR_SIN;		// HP sin select = 1
+			
+			switch_bank(iobase, BANK2);
+      			outb(tmp, iobase+FIR_IRDA_CR);			
+		}
+	}
+			
+	switch_bank(iobase, BANK0);
+	
+	restore_flags(flags);
+		
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");		
+}
+
+/*
+ * Function ali_ircc_sir_write (driver)
+ *
+ *    Fill Tx FIFO with transmit data
+ *
+ */
+static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+		
+	/* Tx FIFO should be empty! */
+	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		return 0;
+	}
+        
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual], iobase+UART_TX);
+
+		actual++;
+	}
+	
+        IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	return actual;
+}
+
+/*
+ * Function ali_ircc_net_init (dev)
+ *
+ *    Initialize network device
+ *
+ */
+static int ali_ircc_net_init(struct net_device *dev)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	/* Setup to be a normal IrDA network device driver */
+	irda_device_setup(dev);
+
+	/* Insert overrides below this line! */
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return 0;
+}
+
+/*
+ * Function ali_ircc_net_open (dev)
+ *
+ *    Start the device
+ *
+ */
+static int ali_ircc_net_open(struct net_device *dev)
+{
+	struct ali_ircc_cb *self;
+	int iobase;
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	ASSERT(dev != NULL, return -1;);
+	
+	self = (struct ali_ircc_cb *) dev->priv;
+	
+	ASSERT(self != NULL, return 0;);
+	
+	iobase = self->io.fir_base;
+	
+	/* Request IRQ and install Interrupt Handler */
+	if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev)) 
+	{
+		WARNING("%s, unable to allocate irq=%d\n", driver_name, 
+			self->io.irq);
+		return -EAGAIN;
+	}
+	
+	/*
+	 * Always allocate the DMA channel after the IRQ, and clean up on 
+	 * failure.
+	 */
+	if (request_dma(self->io.dma, dev->name)) {
+		WARNING("%s, unable to allocate dma=%d\n", driver_name, 
+			self->io.dma);
+		free_irq(self->io.irq, self);
+		return -EAGAIN;
+	}
+	
+	/* Turn on interrups */
+	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
+
+	/* Ready to play! */
+	netif_start_queue(dev); //benjamin by irport
+	
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+		
+	MOD_INC_USE_COUNT;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return 0;
+}
+
+/*
+ * Function ali_ircc_net_close (dev)
+ *
+ *    Stop the device
+ *
+ */
+static int ali_ircc_net_close(struct net_device *dev)
+{	
+
+	struct ali_ircc_cb *self;
+	//int iobase;
+			
+	IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n");
+		
+	ASSERT(dev != NULL, return -1;);
+
+	self = (struct ali_ircc_cb *) dev->priv;
+	ASSERT(self != NULL, return 0;);
+
+	/* Stop device */
+	netif_stop_queue(dev);
+	
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+		
+	disable_dma(self->io.dma);
+
+	/* Disable interrupts */
+	SetCOMInterrupts(self, FALSE);
+	       
+	free_irq(self->io.irq, dev);
+	free_dma(self->io.dma);
+
+	MOD_DEC_USE_COUNT;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return 0;
+}
+
+/*
+ * Function ali_ircc_fir_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame
+ *
+ */
+static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ali_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	int mtt, diff;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	
+	self = (struct ali_ircc_cb *) dev->priv;
+	iobase = self->io.fir_base;
+
+	netif_stop_queue(dev);
+	
+	/* Check if we need to change the speed */
+	speed = irda_get_next_speed(skb);
+	if ((speed != self->io.speed) && (speed != -1)) {
+		/* Check for empty frame */
+		if (!skb->len) {
+			ali_ircc_change_speed(self, speed); 
+			dev_kfree_skb(skb);
+			return 0;
+		} else
+			self->new_speed = speed;
+	}
+
+	spin_lock_irqsave(&self->lock, flags);
+	
+	/* Register and copy this frame to DMA memory */
+	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
+	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
+	self->tx_fifo.tail += skb->len;
+
+	self->stats.tx_bytes += skb->len;
+
+	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
+	       skb->len);
+	
+	self->tx_fifo.len++;
+	self->tx_fifo.free++;
+
+	/* Start transmit only if there is currently no transmit going on */
+	if (self->tx_fifo.len == 1) 
+	{
+		/* Check if we must wait the min turn time or not */
+		mtt = irda_get_mtt(skb);
+				
+		if (mtt) 
+		{
+			/* Check how much time we have used already */
+			get_fast_time(&self->now);
+			
+			diff = self->now.tv_usec - self->stamp.tv_usec;
+			/* self->stamp is set from ali_ircc_dma_receive_complete() */
+							
+			IRDA_DEBUG(1, __FUNCTION__ "(), ******* diff = %d ******* \n", diff);	
+			
+			if (diff < 0) 
+				diff += 1000000;
+			
+			/* Check if the mtt is larger than the time we have
+			 * already used by all the protocol processing
+			 */
+			if (mtt > diff)
+			{				
+				mtt -= diff;
+								
+				/* 
+				 * Use timer if delay larger than 1000 us, and
+				 * use udelay for smaller values which should
+				 * be acceptable
+				 */
+				if (mtt > 500) 
+				{
+					/* Adjust for timer resolution */
+					mtt = (mtt+250) / 500; 	/* 4 discard, 5 get advanced, Let's round off */
+					
+					IRDA_DEBUG(1, __FUNCTION__ "(), ************** mtt = %d ***********\n", mtt);	
+					
+					/* Setup timer */
+					if (mtt == 1) /* 500 us */
+					{
+						switch_bank(iobase, BANK1);
+						outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR);
+					}	
+					else if (mtt == 2) /* 1 ms */
+					{
+						switch_bank(iobase, BANK1);
+						outb(TIMER_IIR_1ms, iobase+FIR_TIMER_IIR);
+					}					
+					else /* > 2ms -> 4ms */
+					{
+						switch_bank(iobase, BANK1);
+						outb(TIMER_IIR_2ms, iobase+FIR_TIMER_IIR);
+					}
+					
+					
+					/* Start timer */
+					outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR);
+					self->io.direction = IO_XMIT;
+					
+					/* Enable timer interrupt */
+					self->ier = IER_TIMER;
+					SetCOMInterrupts(self, TRUE);					
+					
+					/* Timer will take care of the rest */
+					goto out; 
+				} 
+				else
+					udelay(mtt);
+			} // if (if (mtt > diff)
+		}// if (mtt) 
+				
+		/* Enable EOM interrupt */
+		self->ier = IER_EOM;
+		SetCOMInterrupts(self, TRUE);
+		
+		/* Transmit frame */
+		ali_ircc_dma_xmit(self);
+	} // if (self->tx_fifo.len == 1) 
+	
+ out:
+ 	
+	/* Not busy transmitting anymore if window is not full */
+	if (self->tx_fifo.free < MAX_TX_WINDOW)
+		netif_wake_queue(self->netdev);
+	
+	/* Restore bank register */
+	switch_bank(iobase, BANK0);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+	dev_kfree_skb(skb);
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	return 0;	
+}
+
+
+static void ali_ircc_dma_xmit(struct ali_ircc_cb *self)
+{
+	int iobase, tmp;
+	unsigned char FIFO_OPTI, Hi, Lo;
+	
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	
+	iobase = self->io.fir_base;
+	
+	/* FIFO threshold , this method comes from NDIS5 code */
+	
+	if(self->tx_fifo.queue[self->tx_fifo.ptr].len < TX_FIFO_Threshold)
+		FIFO_OPTI = self->tx_fifo.queue[self->tx_fifo.ptr].len-1;
+	else
+		FIFO_OPTI = TX_FIFO_Threshold;
+	
+	/* Disable DMA */
+	switch_bank(iobase, BANK1);
+	outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR);
+	
+	self->io.direction = IO_XMIT;
+	
+	setup_dma(self->io.dma, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].start, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].len, 
+		  DMA_TX_MODE);
+		
+	/* Reset Tx FIFO */
+	switch_bank(iobase, BANK0);
+	outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A);
+	
+	/* Set Tx FIFO threshold */
+	if (self->fifo_opti_buf!=FIFO_OPTI) 
+	{
+		switch_bank(iobase, BANK1);
+	    	outb(FIFO_OPTI, iobase+FIR_FIFO_TR) ;
+	    	self->fifo_opti_buf=FIFO_OPTI;
+	}
+	
+	/* Set Tx DMA threshold */
+	switch_bank(iobase, BANK1);
+	outb(TX_DMA_Threshold, iobase+FIR_DMA_TR);
+	
+	/* Set max Tx frame size */
+	Hi = (self->tx_fifo.queue[self->tx_fifo.ptr].len >> 8) & 0x0f;
+	Lo = self->tx_fifo.queue[self->tx_fifo.ptr].len & 0xff;
+	switch_bank(iobase, BANK2);
+	outb(Hi, iobase+FIR_TX_DSR_HI);
+	outb(Lo, iobase+FIR_TX_DSR_LO);
+	
+	/* Disable SIP , Disable Brick Wall (we don't support in TX mode), Change to TX mode */
+	switch_bank(iobase, BANK0);	
+	tmp = inb(iobase+FIR_LCR_B);
+	tmp &= ~0x20; // Disable SIP
+	outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B);
+	IRDA_DEBUG(1, __FUNCTION__ "(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", inb(iobase+FIR_LCR_B));
+	
+	outb(0, iobase+FIR_LSR);
+			
+	/* Enable DMA and Burst Mode */
+	switch_bank(iobase, BANK1);
+	outb(inb(iobase+FIR_CR) | CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR);
+	
+	switch_bank(iobase, BANK0); 
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");
+}
+
+static int  ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self)
+{
+	int iobase;
+	int ret = TRUE;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	
+	iobase = self->io.fir_base;
+	
+	/* Disable DMA */
+	switch_bank(iobase, BANK1);
+	outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR);
+	
+	/* Check for underrun! */
+	switch_bank(iobase, BANK0);
+	if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT)
+	
+	{
+		ERROR(__FUNCTION__ "(), ********* LSR_FRAME_ABORT *********\n");	
+		self->stats.tx_errors++;
+		self->stats.tx_fifo_errors++;		
+	}
+	else 
+	{
+		self->stats.tx_packets++;
+	}
+
+	/* Check if we need to change the speed */
+	if (self->new_speed) 
+	{
+		ali_ircc_change_speed(self, self->new_speed);
+		self->new_speed = 0;
+	}
+
+	/* Finished with this frame, so prepare for next */
+	self->tx_fifo.ptr++;
+	self->tx_fifo.len--;
+
+	/* Any frames to be sent back-to-back? */
+	if (self->tx_fifo.len) 
+	{
+		ali_ircc_dma_xmit(self);
+		
+		/* Not finished yet! */
+		ret = FALSE;
+	} 
+	else 
+	{	/* Reset Tx FIFO info */
+		self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+		self->tx_fifo.tail = self->tx_buff.head;
+	}
+
+	/* Make sure we have room for more frames */
+	if (self->tx_fifo.free < MAX_TX_WINDOW) {
+		/* Not busy transmitting anymore */
+		/* Tell the network layer, that we can accept more frames */
+		netif_wake_queue(self->netdev);
+	}
+		
+	switch_bank(iobase, BANK0); 
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	return ret;
+}
+
+/*
+ * Function ali_ircc_dma_receive (self)
+ *
+ *    Get ready for receiving a frame. The device will initiate a DMA
+ *    if it starts to receive a frame.
+ *
+ */
+static int ali_ircc_dma_receive(struct ali_ircc_cb *self) 
+{
+	int iobase, tmp;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+	
+	iobase = self->io.fir_base;
+	
+	/* Reset Tx FIFO info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+		
+	/* Disable DMA */
+	switch_bank(iobase, BANK1);
+	outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR);
+	
+	/* Reset Message Count */
+	switch_bank(iobase, BANK0);
+	outb(0x07, iobase+FIR_LSR);
+		
+	self->rcvFramesOverflow = FALSE;	
+	
+	self->LineStatus = inb(iobase+FIR_LSR) ;
+	
+	/* Reset Rx FIFO info */
+	self->io.direction = IO_RECV;
+	self->rx_buff.data = self->rx_buff.head;
+		
+	/* Reset Rx FIFO */
+	// switch_bank(iobase, BANK0);
+	outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); 
+	
+	self->st_fifo.len = self->st_fifo.pending_bytes = 0;
+	self->st_fifo.tail = self->st_fifo.head = 0;
+		
+	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
+		  DMA_RX_MODE);	
+	 
+	/* Set Receive Mode,Brick Wall */
+	//switch_bank(iobase, BANK0);
+	tmp = inb(iobase+FIR_LCR_B);
+	outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM
+	IRDA_DEBUG(1, __FUNCTION__ "(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", inb(iobase+FIR_LCR_B));
+			
+	/* Set Rx Threshold */
+	switch_bank(iobase, BANK1);
+	outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR);
+	outb(RX_DMA_Threshold, iobase+FIR_DMA_TR);
+		
+	/* Enable DMA and Burst Mode */
+	// switch_bank(iobase, BANK1);
+	outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR);
+				
+	switch_bank(iobase, BANK0); 
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	return 0;
+}
+
+static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
+{
+	struct st_fifo *st_fifo;
+	struct sk_buff *skb;
+	__u8 status, MessageCount;
+	int len, i, iobase, val;	
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n");	
+
+	st_fifo = &self->st_fifo;		
+	iobase = self->io.fir_base;	
+		
+	switch_bank(iobase, BANK0);
+	MessageCount = inb(iobase+ FIR_LSR)&0x07;
+	
+	if (MessageCount > 0)	
+		IRDA_DEBUG(0, __FUNCTION__ "(), Messsage count = %d,\n", MessageCount);	
+		
+	for (i=0; i<=MessageCount; i++)
+	{
+		/* Bank 0 */
+		switch_bank(iobase, BANK0);
+		status = inb(iobase+FIR_LSR);
+		
+		switch_bank(iobase, BANK2);
+		len = inb(iobase+FIR_RX_DSR_HI) & 0x0f;
+		len = len << 8; 
+		len |= inb(iobase+FIR_RX_DSR_LO);
+		
+		IRDA_DEBUG(1, __FUNCTION__ "(), RX Length = 0x%.2x,\n", len);	
+		IRDA_DEBUG(1, __FUNCTION__ "(), RX Status = 0x%.2x,\n", status);
+		
+		if (st_fifo->tail >= MAX_RX_WINDOW) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n");
+			continue;
+		}
+			
+		st_fifo->entries[st_fifo->tail].status = status;
+		st_fifo->entries[st_fifo->tail].len = len;
+		st_fifo->pending_bytes += len;
+		st_fifo->tail++;
+		st_fifo->len++;
+	}
+			
+	for (i=0; i<=MessageCount; i++)
+	{	
+		/* Get first entry */
+		status = st_fifo->entries[st_fifo->head].status;
+		len    = st_fifo->entries[st_fifo->head].len;
+		st_fifo->pending_bytes -= len;
+		st_fifo->head++;
+		st_fifo->len--;			
+		
+		/* Check for errors */
+		if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) 		
+		{
+			IRDA_DEBUG(0,__FUNCTION__ "(), ************* RX Errors ************ \n");	
+			
+			/* Skip frame */
+			self->stats.rx_errors++;
+			
+			self->rx_buff.data += len;
+			
+			if (status & LSR_FIFO_UR) 
+			{
+				self->stats.rx_frame_errors++;
+				IRDA_DEBUG(0,__FUNCTION__ "(), ************* FIFO Errors ************ \n");
+			}	
+			if (status & LSR_FRAME_ERROR)
+			{
+				self->stats.rx_frame_errors++;
+				IRDA_DEBUG(0,__FUNCTION__ "(), ************* FRAME Errors ************ \n");
+			}
+							
+			if (status & LSR_CRC_ERROR) 
+			{
+				self->stats.rx_crc_errors++;
+				IRDA_DEBUG(0,__FUNCTION__ "(), ************* CRC Errors ************ \n");
+			}
+			
+			if(self->rcvFramesOverflow)
+			{
+				self->stats.rx_frame_errors++;
+				IRDA_DEBUG(0,__FUNCTION__ "(), ************* Overran DMA buffer ************ \n");								
+			}
+			if(len == 0)
+			{
+				self->stats.rx_frame_errors++;
+				IRDA_DEBUG(0,__FUNCTION__ "(), ********** Receive Frame Size = 0 ********* \n");
+			}
+		}	 
+		else 
+		{
+			
+			if (st_fifo->pending_bytes < 32) 
+			{
+				switch_bank(iobase, BANK0);
+				val = inb(iobase+FIR_BSR);	
+				if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) 
+				{
+					IRDA_DEBUG(0, __FUNCTION__ "(), ************* BSR_FIFO_NOT_EMPTY ************ \n");
+					
+					/* Put this entry back in fifo */
+					st_fifo->head--;
+					st_fifo->len++;
+					st_fifo->pending_bytes += len;
+					st_fifo->entries[st_fifo->head].status = status;
+					st_fifo->entries[st_fifo->head].len = len;
+						
+					/*  
+		 			* DMA not finished yet, so try again 
+		 			* later, set timer value, resolution 
+		 			* 500 us 
+		 			*/
+					 
+					switch_bank(iobase, BANK1);
+					outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); // 2001/1/2 05:07PM
+					
+					/* Enable Timer */
+					outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR);
+						
+					return FALSE; /* I'll be back! */
+				}
+			}		
+			
+			/* 
+			 * Remember the time we received this frame, so we can
+			 * reduce the min turn time a bit since we will know
+			 * how much time we have used for protocol processing
+			 */
+			get_fast_time(&self->stamp);
+
+			skb = dev_alloc_skb(len+1);
+			if (skb == NULL)  
+			{
+				WARNING(__FUNCTION__ "(), memory squeeze, "
+					"dropping frame.\n");
+				self->stats.rx_dropped++;
+
+				return FALSE;
+			}
+			
+			/* Make sure IP header gets aligned */
+			skb_reserve(skb, 1); 
+			
+			/* Copy frame without CRC, CRC is removed by hardware*/
+			skb_put(skb, len);
+			memcpy(skb->data, self->rx_buff.data, len);
+
+			/* Move to next frame */
+			self->rx_buff.data += len;
+			self->stats.rx_bytes += len;
+			self->stats.rx_packets++;
+
+			skb->dev = self->netdev;
+			skb->mac.raw  = skb->data;
+			skb->protocol = htons(ETH_P_IRDA);
+			netif_rx(skb);
+		}
+	}
+	
+	switch_bank(iobase, BANK0);	
+		
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	return TRUE;
+}
+
+
+
+/*
+ * Function ali_ircc_sir_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame!
+ *
+ */
+static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ali_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	ASSERT(dev != NULL, return 0;);
+	
+	self = (struct ali_ircc_cb *) dev->priv;
+	ASSERT(self != NULL, return 0;);
+
+	iobase = self->io.sir_base;
+
+	netif_stop_queue(dev);
+	
+	/* Check if we need to change the speed */
+	speed = irda_get_next_speed(skb);
+	if ((speed != self->io.speed) && (speed != -1)) {
+		/* Check for empty frame */
+		if (!skb->len) {
+			ali_ircc_change_speed(self, speed); 
+			dev_kfree_skb(skb);
+			return 0;
+		} else
+			self->new_speed = speed;
+	}
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Init tx buffer */
+	self->tx_buff.data = self->tx_buff.head;
+
+        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
+	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+					   self->tx_buff.truesize);
+	
+	self->stats.tx_bytes += self->tx_buff.len;
+
+	/* Turn on transmit finished interrupt. Will fire immediately!  */
+	outb(UART_IER_THRI, iobase+UART_IER); 
+
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	dev_kfree_skb(skb);
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return 0;	
+}
+
+
+/*
+ * Function ali_ircc_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct ali_ircc_cb *self;
+	unsigned long flags;
+	int ret = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();	
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSBANDWIDTH\n");
+		/*
+		 * This function will also be used by IrLAP to change the
+		 * speed, so we still must allow for speed change within
+		 * interrupt context.
+		 */
+		if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+			return -EPERM;
+		
+		ali_ircc_change_speed(self, irq->ifr_baudrate);		
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSMEDIABUSY\n");
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		IRDA_DEBUG(2, __FUNCTION__ "(), SIOCGRECEIVING\n");
+		irq->ifr_receiving = ali_ircc_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return ret;
+}
+
+/*
+ * Function ali_ircc_is_receiving (self)
+ *
+ *    Return TRUE is we are currently receiving a frame
+ *
+ */
+static int ali_ircc_is_receiving(struct ali_ircc_cb *self)
+{
+	unsigned long flags;
+	int status = FALSE;
+	int iobase;		
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start -----------------\n");
+	
+	ASSERT(self != NULL, return FALSE;);
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	if (self->io.speed > 115200) 
+	{
+		iobase = self->io.fir_base;
+		
+		switch_bank(iobase, BANK1);
+		if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) 		
+		{
+			/* We are receiving something */
+			IRDA_DEBUG(1, __FUNCTION__ "(), We are receiving something\n");
+			status = TRUE;
+		}
+		switch_bank(iobase, BANK0);		
+	} 
+	else
+	{ 
+		status = (self->rx_buff.state != OUTSIDE_FRAME);
+	}
+	
+	spin_unlock_irqrestore(&self->lock, flags);
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");
+	
+	return status;
+}
+
+static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev)
+{
+	struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	
+	return &self->stats;
+}
+
+static void ali_ircc_suspend(struct ali_ircc_cb *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	MESSAGE("%s, Suspending\n", driver_name);
+
+	if (self->io.suspended)
+		return;
+
+	ali_ircc_net_close(self->netdev);
+
+	self->io.suspended = 1;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static void ali_ircc_wakeup(struct ali_ircc_cb *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	if (!self->io.suspended)
+		return;
+	
+	ali_ircc_net_open(self->netdev);
+	
+	MESSAGE("%s, Waking up\n", driver_name);
+
+	self->io.suspended = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+        struct ali_ircc_cb *self = (struct ali_ircc_cb*) dev->data;
+        
+        IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+        if (self) {
+                switch (rqst) {
+                case PM_SUSPEND:
+                        ali_ircc_suspend(self);
+                        break;
+                case PM_RESUME:
+                        ali_ircc_wakeup(self);
+                        break;
+                }
+        }
+        
+        IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+        
+	return 0;
+}
+
+
+/* ALi Chip Function */
+
+static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable)
+{
+	
+	unsigned char newMask;
+	
+	int iobase = self->io.fir_base; /* or sir_base */
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), -------- Start -------- ( Enable = %d )\n", enable);	
+	
+	/* Enable the interrupt which we wish to */
+	if (enable){
+		if (self->io.direction == IO_XMIT)
+		{
+			if (self->io.speed > 115200) /* FIR, MIR */
+			{
+				newMask = self->ier;
+			}
+			else /* SIR */
+			{
+				newMask = UART_IER_THRI | UART_IER_RDI;
+			}
+		}
+		else {
+			if (self->io.speed > 115200) /* FIR, MIR */
+			{
+				newMask = self->ier;
+			}
+			else /* SIR */
+			{
+				newMask = UART_IER_RDI;
+			}
+		}
+	}
+	else /* Disable all the interrupts */
+	{
+		newMask = 0x00;
+
+	}
+
+	//SIR and FIR has different registers
+	if (self->io.speed > 115200)
+	{	
+		switch_bank(iobase, BANK0);
+		outb(newMask, iobase+FIR_IER);
+	}
+	else
+		outb(newMask, iobase+UART_IER);
+		
+	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static void SIR2FIR(int iobase)
+{
+	//unsigned char tmp;
+	unsigned long flags;
+		
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	save_flags(flags);
+	cli();
+	
+	outb(0x28, iobase+UART_MCR);
+	outb(0x68, iobase+UART_MCR);
+	outb(0x88, iobase+UART_MCR);		
+	
+	restore_flags(flags);
+		
+	outb(0x60, iobase+FIR_MCR); 	/*  Master Reset */
+	outb(0x20, iobase+FIR_MCR); 	/*  Master Interrupt Enable */
+	
+	//tmp = inb(iobase+FIR_LCR_B);	/* SIP enable */
+	//tmp |= 0x20;
+	//outb(tmp, iobase+FIR_LCR_B);	
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");	
+}
+
+static void FIR2SIR(int iobase)
+{
+	unsigned char val;
+	unsigned long flags;
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	
+	save_flags(flags);
+	cli();
+	
+	outb(0x20, iobase+FIR_MCR); 	/* IRQ to low */
+	outb(0x00, iobase+UART_IER); 	
+		
+	outb(0xA0, iobase+FIR_MCR); 	/* Don't set master reset */
+	outb(0x00, iobase+UART_FCR);
+	outb(0x07, iobase+UART_FCR);		
+	
+	val = inb(iobase+UART_RX);
+	val = inb(iobase+UART_LSR);
+	val = inb(iobase+UART_MSR);
+	
+	restore_flags(flags);
+	
+	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>");
+MODULE_DESCRIPTION("ALi FIR Controller Driver");
+
+MODULE_PARM(io,  "1-4i");
+MODULE_PARM_DESC(io, "Base I/O addresses");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM_DESC(irq, "IRQ lines");
+MODULE_PARM(dma, "1-4i");
+MODULE_PARM_DESC(dma, "DMA channels");
+
+int init_module(void)
+{
+	return ali_ircc_init();	
+}
+
+void cleanup_module(void)
+{
+	ali_ircc_cleanup();
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- v2.4.6/linux/drivers/net/irda/irport.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/irda/irport.c	Wed Jul  4 11:50:38 2001
@@ -951,13 +951,17 @@
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		irda_task_execute(self, __irport_change_speed, NULL, NULL, 
-				  (void *) irq->ifr_baudrate);
+			ret = -EPERM;
+                else
+			irda_task_execute(self, __irport_change_speed, NULL, 
+					  NULL, (void *) irq->ifr_baudrate);
 		break;
 	case SIOCSDONGLE: /* Set dongle */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+
 		/* Initialize dongle */
 		dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
 		if (!dongle)
@@ -978,16 +982,22 @@
 				  NULL);	
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+
 		irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		irq->ifr_receiving = irport_is_receiving(self);
 		break;
 	case SIOCSDTRRTS:
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+
 		irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
 		break;
 	default:
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.4.6/linux/drivers/net/irda/irtty.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/irda/irtty.c	Wed Jul  4 11:50:38 2001
@@ -971,13 +971,17 @@
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		irda_task_execute(self, irtty_change_speed, NULL, NULL, 
-				  (void *) irq->ifr_baudrate);
+			ret = -EPERM;
+		else
+			irda_task_execute(self, irtty_change_speed, NULL, NULL, 
+					  (void *) irq->ifr_baudrate);
 		break;
 	case SIOCSDONGLE: /* Set dongle */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+
 		/* Initialize dongle */
 		dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
 		if (!dongle)
@@ -999,21 +1003,24 @@
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		irda_device_set_media_busy(self->netdev, TRUE);
+			ret = -EPERM;
+		else
+			irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		irq->ifr_receiving = irtty_is_receiving(self);
 		break;
 	case SIOCSDTRRTS:
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+			ret = -EPERM;
+		else
+			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		irtty_set_mode(dev, irq->ifr_mode);
+			ret = -EPERM;
+		else
+			irtty_set_mode(dev, irq->ifr_mode);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- v2.4.6/linux/drivers/net/irda/nsc-ircc.c	Tue May  1 16:05:00 2001
+++ linux/drivers/net/irda/nsc-ircc.c	Wed Jul  4 11:50:38 2001
@@ -90,7 +90,7 @@
 static nsc_chip_t chips[] = {
 	{ "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, 
 	  nsc_ircc_probe_108, nsc_ircc_init_108 },
-	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0, 
+	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8, 
 	  nsc_ircc_probe_338, nsc_ircc_init_338 },
 	{ NULL }
 };
@@ -160,7 +160,7 @@
 	int i = 0;
 
 	/* Probe for all the NSC chipsets we know about */
-	for (chip=chips; chip->name ; chip++,i++) {
+	for (chip=chips; chip->name ; chip++) {
 		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", 
 			   chip->name);
 		
@@ -196,7 +196,7 @@
 				 * we init the chip, if not we probe the values
 				 * set by the BIOS
 				 */				
-				if (io[i] < 2000) {
+				if (io[i] < 0x2000) {
 					chip->init(chip, &info);
 				} else
 					chip->probe(chip, &info);
@@ -602,7 +602,7 @@
 	outb(CFG_PNP0, cfg_base);
 	reg = inb(cfg_base+1);
 	
-	pnp = (reg >> 4) & 0x01;
+	pnp = (reg >> 3) & 0x01;
 	if (pnp) {
 		IRDA_DEBUG(2, "(), Chip is in PnP mode\n");
 		outb(0x46, cfg_base);
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- v2.4.6/linux/drivers/net/irda/smc-ircc.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/irda/smc-ircc.c	Wed Jul  4 11:50:38 2001
@@ -98,6 +98,8 @@
 	{ "FDC37N769", 0x55, 0x55, 0x0d, 0x28, ircc_probe_69 },
 	{ "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 },
 	{ "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 },
+	{ "FDC37N971", 0x55, 0x55, 0x20, 0x0a, ircc_probe_58 },
+	{ "FDC37N972", 0x55, 0x55, 0x20, 0x0b, ircc_probe_58 },
 	{ NULL }
 };
 
@@ -127,7 +129,7 @@
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
 	/* Probe for all the NSC chipsets we know about */
-	for (chip=chips; chip->name ; chip++,i++) {
+	for (chip=chips; chip->name ; chip++) {
 		for (i=0; i<2; i++) {
 			info.cfg_base = smcreg[i];
 			
@@ -136,7 +138,7 @@
                          * parameters which we should use instead of probed
 			 * values
 			 */
-			if (io[i] < 2000) {
+			if (io[i] < 0x2000) {
 				info.fir_base = io[i];
 				info.sir_base = io2[i];
 			} else if (chip->probe(chip, &info) < 0)
diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.4.6/linux/drivers/net/irda/toshoboe.c	Tue May  1 16:05:00 2001
+++ linux/drivers/net/irda/toshoboe.c	Wed Jul  4 11:50:38 2001
@@ -43,9 +43,6 @@
 /* Define this to enable FIR and MIR support */
 #define ENABLE_FAST
 
-/* Number of ports this driver can support, you also need to edit dev_self below */
-#define NSELFS 4
-
 /* Size of IO window */
 #define CHIP_IO_EXTENT	0x1f
 
@@ -77,7 +74,6 @@
 #include <net/irda/irda_device.h>
 
 #include <linux/pm.h>
-static int toshoboe_pmproc (struct pm_dev *dev, pm_request_t rqst, void *data);
 
 #include <net/irda/toshoboe.h>
 
@@ -92,8 +88,6 @@
 
 static const char *driver_name = "toshoboe";
 
-static struct toshoboe_cb *dev_self[NSELFS + 1];
-
 static int max_baud = 4000000;
 
 /* Shutdown the chip and point the taskfile reg somewhere else */
@@ -644,21 +638,20 @@
 	return ret;
 }
 
-#ifdef MODULE
-
 MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver");
 MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>");
 MODULE_PARM (max_baud, "i");
 MODULE_PARM_DESC(max_baus, "Maximum baud rate");
 
-static int
-toshoboe_close (struct toshoboe_cb *self)
+static void
+toshoboe_remove (struct pci_dev *pci_dev)
 {
   int i;
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
 
   IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
-  ASSERT (self != NULL, return -1;
+  ASSERT (self != NULL, return;
     );
 
   if (!self->stopped)
@@ -693,16 +686,12 @@
   self->taskfilebuf = NULL;
   self->taskfile = NULL;
 
-  return (0);
+  return;
 
 }
 
-#endif
-
-
-
 static int
-toshoboe_open (struct pci_dev *pci_dev)
+toshoboe_probe (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
 {
   struct toshoboe_cb *self;
   struct net_device *dev;
@@ -713,15 +702,6 @@
 
   IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
-  while (dev_self[i])
-    i++;
-
-  if (i == NSELFS)
-    {
-      printk (KERN_ERR "Oboe: No more instances available");
-      return -ENOMEM;
-    }
-
   if ((err=pci_enable_device(pci_dev)))
 	  return err;
 
@@ -736,12 +716,10 @@
 
   memset (self, 0, sizeof (struct toshoboe_cb));
 
-  dev_self[i] = self;           /*This needs moving if we ever get more than one chip */
-
   self->open = 0;
   self->stopped = 0;
   self->pdev = pci_dev;
-  self->base = pci_dev->resource[0].start;
+  self->base = pci_resource_start(pci_dev,0);
 
   self->io.sir_base = self->base;
   self->io.irq = pci_dev->irq;
@@ -749,19 +727,15 @@
   self->io.speed = 9600;
 
   /* Lock the port that we need */
-  i = check_region (self->io.sir_base, self->io.sir_ext);
-  if (i < 0)
+  if (NULL==request_region (self->io.sir_base, self->io.sir_ext, driver_name))
     {
       IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
              self->io.sir_base);
 
-      dev_self[i] = NULL;
-      kfree (self);
-
-      return -ENODEV;
+      err = -EBUSY;
+      goto freeself;
     }
 
-
   irda_init_max_qos_capabilies (&self->qos);
   self->qos.baud_rate.bits = 0;
 
@@ -804,8 +778,8 @@
   if (!self->taskfilebuf)
     {
       printk (KERN_ERR "toshoboe: kmalloc for DMA failed()\n");
-      kfree (self);
-      return -ENOMEM;
+      err = -ENOMEM;
+      goto freeregion;
     }
 
 
@@ -839,25 +813,16 @@
   if (ok != RX_SLOTS + TX_SLOTS)
     {
       printk (KERN_ERR "toshoboe: kmalloc for buffers failed()\n");
+      err = -ENOMEM;
+      goto freebufs;
 
+  }
 
-      for (i = 0; i < TX_SLOTS; ++i)
-        if (self->xmit_bufs[i])
-          kfree (self->xmit_bufs[i]);
-      for (i = 0; i < RX_SLOTS; ++i)
-        if (self->recv_bufs[i])
-          kfree (self->recv_bufs[i]);
-
-      kfree (self);
-      return -ENOMEM;
-
-    }
-
-  request_region (self->io.sir_base, self->io.sir_ext, driver_name);
 
   if (!(dev = dev_alloc("irda%d", &err))) {
-	  ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
-	  return -ENOMEM;
+      ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+      err = -ENOMEM;
+      goto freebufs;
   }
   dev->priv = (void *) self;
   self->netdev = dev;
@@ -875,12 +840,15 @@
   rtnl_unlock();
   if (err) {
 	  ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
-	  return -1;
+	  /* XXX there is not freeing for dev? */
+          goto freebufs;
   }
+  pci_set_drvdata(pci_dev,self);
 
-  pmdev = pm_register (PM_PCI_DEV, PM_PCI_ID(pci_dev), toshoboe_pmproc);
+/*  pmdev = pm_register (PM_PCI_DEV, PM_PCI_ID(pci_dev), toshoboe_pmproc);
   if (pmdev)
 	  pmdev->data = self;
+	  */
 
   printk (KERN_WARNING "ToshOboe: Using ");
 #ifdef ONETASK
@@ -891,22 +859,36 @@
   printk (" tasks, version %s\n", rcsid);
 
   return (0);
+freebufs:
+      for (i = 0; i < TX_SLOTS; ++i)
+        if (self->xmit_bufs[i])
+          kfree (self->xmit_bufs[i]);
+      for (i = 0; i < RX_SLOTS; ++i)
+        if (self->recv_bufs[i])
+          kfree (self->recv_bufs[i]);
+      kfree(self->taskfilebuf);
+freeregion:
+      release_region (self->io.sir_base, self->io.sir_ext);
+freeself:
+      kfree (self);
+      return err;
 }
 
-static void 
-toshoboe_gotosleep (struct toshoboe_cb *self)
+static int
+toshoboe_suspend (struct pci_dev *pci_dev, u32 crap)
 {
   int i = 10;
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
 
   printk (KERN_WARNING "ToshOboe: suspending\n");
 
-  if (self->stopped)
-    return;
+  if (!self || self->stopped)
+    return 0;
 
   self->stopped = 1;
 
   if (!self->open)
-    return;
+    return 0;
 
 /*FIXME: can't sleep here wait one second */
 
@@ -917,22 +899,26 @@
   toshoboe_disablebm (self);
 
   self->txpending = 0;
-
+  return 0;
 }
 
 
-static void 
-toshoboe_wakeup (struct toshoboe_cb *self)
+static int 
+toshoboe_resume (struct pci_dev *pci_dev)
 {
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
   unsigned long flags;
 
+  if (!self)
+    return 0;
+
   if (!self->stopped)
-    return;
+    return 0;
 
   if (!self->open)
     {
       self->stopped = 0;
-      return;
+      return 0;
     }
 
   save_flags (flags);
@@ -949,108 +935,29 @@
   netif_wake_queue(self->netdev);
   restore_flags (flags);
   printk (KERN_WARNING "ToshOboe: waking up\n");
-
-}
-
-static int 
-toshoboe_pmproc (struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-  struct toshoboe_cb *self = (struct toshoboe_cb *) dev->data;
-  if (self) {
-	  switch (rqst) {
-	  case PM_SUSPEND:
-		  toshoboe_gotosleep (self);
-		  break;
-	  case PM_RESUME:
-		  toshoboe_wakeup (self);
-		  break;
-	  }
-  }
   return 0;
 }
 
+static struct pci_driver toshoboe_pci_driver = {
+  name		: "toshoboe",
+  id_table	: toshoboe_pci_tbl,
+  probe		: toshoboe_probe,
+  remove	: toshoboe_remove,
+  suspend	: toshoboe_suspend,
+  resume	: toshoboe_resume 
+};
 
-int __init toshoboe_init (void)
-{
-  struct pci_dev *pci_dev = NULL;
-  int found = 0;
-
-  do
-    {
-      pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
-                                 PCI_DEVICE_ID_FIR701, pci_dev);
-      if (pci_dev)
-        {
-          printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
-		  pci_dev->resource[0].start,
-                  pci_dev->irq);
-
-          if (!toshoboe_open (pci_dev))
-	      found++;
-        }
-
-    }
-  while (pci_dev);
-
-  if (!found) do
-    {
-      pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
-                                 PCI_DEVICE_ID_FIR701b, pci_dev);
-      if (pci_dev)
-        {
-          printk (KERN_WARNING "ToshOboe: Found 701b chip at 0x%0lx irq %d\n",
-		  pci_dev->resource[0].start,
-                  pci_dev->irq);
-
-          if (!toshoboe_open (pci_dev))
-	      found++;
-        }
-
-    }
-  while (pci_dev);
-
-
-
-  if (found)
-    {
-      return 0;
-    }
-
-  return -ENODEV;
-}
-
-#ifdef MODULE
-
-static void
-toshoboe_cleanup (void)
-{
-  int i;
-
-  IRDA_DEBUG (4, __FUNCTION__ "()\n");
-
-  for (i = 0; i < 4; i++)
-    {
-      if (dev_self[i])
-        toshoboe_close (dev_self[i]);
-    }
-
-  pm_unregister_all (toshoboe_pmproc);
-}
-
-
-
-int
-init_module (void)
-{
-  return toshoboe_init ();
+int __init
+toshoboe_init (void) {
+  pci_module_init(&toshoboe_pci_driver);
+  return 0;
 }
 
-
 void
-cleanup_module (void)
+toshoboe_cleanup (void)
 {
-  toshoboe_cleanup ();
+  pci_unregister_driver(&toshoboe_pci_driver);
 }
 
-
-#endif
+module_init(toshoboe_init);
+module_exit(toshoboe_cleanup);
diff -u --recursive --new-file v2.4.6/linux/drivers/net/lp486e.c linux/drivers/net/lp486e.c
--- v2.4.6/linux/drivers/net/lp486e.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/lp486e.c	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,1358 @@
+/* Intel Professional Workstation/panther ethernet driver */
+/* lp486e.c: A panther 82596 ethernet driver for linux. */
+/*
+    History and copyrights:
+
+    Driver skeleton
+        Written 1993 by Donald Becker.
+        Copyright 1993 United States Government as represented by the Director,
+        National Security Agency.  This software may only be used and
+	distributed according to the terms of the GNU Public License
+	as modified by SRC, incorporated herein by reference.
+
+        The author may be reached as becker@super.org or
+        C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+    Apricot
+        Written 1994 by Mark Evans.
+        This driver is for the Apricot 82596 bus-master interface
+
+        Modularised 12/94 Mark Evans
+
+    Professional Workstation
+	Derived from apricot.c by Ard van Breemen
+	<ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
+
+	Credits:
+	Thanks to Murphy Software BV for letting me write this in their time.
+	Well, actually, I get payed doing this...
+	(Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
+	more information on the Professional Workstation)
+
+    Present version
+	aeb@cwi.nl
+*/
+/*
+    There are currently two motherboards that I know of in the
+    professional workstation. The only one that I know is the
+    intel panther motherboard. -- ard
+*/
+/*
+The pws is equipped with an intel 82596. This is a very intelligent controller
+which runs its own micro-code. Communication with the hostprocessor is done
+through linked lists of commands and buffers in the hostprocessors memory.
+A complete description of the 82596 is available from intel. Search for
+a file called "29021806.pdf". It is a complete description of the chip itself.
+To use it for the pws some additions are needed regarding generation of
+the PORT and CA signal, and the interrupt glue needed for a pc.
+I/O map:
+PORT  SIZE ACTION MEANING
+0xCB0    2 WRITE  Lower 16 bits for PORT command
+0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command
+0xCB4    1 WRITE  Generation of CA signal
+0xCB8    1 WRITE  Clear interrupt glue
+All other communication is through memory!
+*/
+
+#define SLOW_DOWN_IO udelay(5);
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.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/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+/* debug print flags */
+#define LOG_SRCDST    0x80000000
+#define LOG_STATINT   0x40000000
+#define LOG_STARTINT  0x20000000
+
+#define i596_debug debug
+
+static int i596_debug = 0;
+
+static const char * const medianame[] = {
+	"10baseT", "AUI",
+	"10baseT-FD", "AUI-FD",
+};
+
+#define LP486E_TOTAL_SIZE 16
+
+#define I596_NULL (0xffffffff)
+
+#define CMD_EOL		0x8000	/* The last command of the list, stop. */
+#define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
+#define CMD_INTR	0x2000	/* Interrupt after doing cmd. */
+
+#define CMD_FLEX	0x0008	/* Enable flexible memory model */
+
+enum commands {
+	CmdNOP = 0,
+	CmdIASetup = 1,
+	CmdConfigure = 2,
+	CmdMulticastList = 3,
+	CmdTx = 4,
+	CmdTDR = 5,
+	CmdDump = 6,
+	CmdDiagnose = 7
+};
+
+char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
+			"Tx", "TDR", "Dump", "Diagnose" };
+
+/* Status word bits */
+#define	STAT_CX		0x8000	/* The CU finished executing a command
+				   with the Interrupt bit set */
+#define	STAT_FR		0x4000	/* The RU finished receiving a frame */
+#define	STAT_CNA	0x2000	/* The CU left the active state */
+#define	STAT_RNR	0x1000	/* The RU left the active state */
+#define STAT_ACK	(STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
+#define	STAT_CUS	0x0700	/* Status of CU: 0: idle, 1: suspended,
+				   2: active, 3-7: unused */
+#define STAT_RUS	0x00f0	/* Status of RU: 0: idle, 1: suspended,
+				   2: no resources, 4: ready,
+				   10: no resources due to no more RBDs,
+				   12: no more RBDs, other: unused */
+#define	STAT_T		0x0008	/* Bus throttle timers loaded */
+#define	STAT_ZERO	0x0807	/* Always zero */
+
+#if 0
+static char *CUstates[8] = {
+	"idle", "suspended", "active", 0, 0, 0, 0, 0
+};
+static char *RUstates[16] = {
+	"idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
+	0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
+};
+
+static void
+i596_out_status(int status) {
+	int bad = 0;
+	char *s;
+
+	printk("status %4.4x:", status);
+	if (status == 0xffff)
+		printk(" strange..\n");
+	else {
+		if (status & STAT_CX)
+			printk("  CU done");
+		if (status & STAT_CNA)
+			printk("  CU stopped");
+		if (status & STAT_FR)
+			printk("  got a frame");
+		if (status & STAT_RNR)
+			printk("  RU stopped");
+		if (status & STAT_T)
+			printk("  throttled");
+		if (status & STAT_ZERO)
+			bad = 1;
+		s = CUstates[(status & STAT_CUS) >> 8];
+		if (!s)
+			bad = 1;
+		else
+			printk("  CU(%s)", s);
+		s = RUstates[(status & STAT_RUS) >> 4];
+		if (!s)
+			bad = 1;
+		else
+			printk("  RU(%s)", s);
+		if (bad)
+			printk("  bad status");
+		printk("\n");
+	}
+}
+#endif
+
+/* Command word bits */
+#define ACK_CX		0x8000
+#define ACK_FR		0x4000
+#define ACK_CNA		0x2000
+#define ACK_RNR		0x1000
+
+#define CUC_START	0x0100
+#define CUC_RESUME	0x0200
+#define CUC_SUSPEND	0x0300
+#define CUC_ABORT	0x0400
+
+#define RX_START	0x0010
+#define RX_RESUME	0x0020
+#define RX_SUSPEND	0x0030
+#define RX_ABORT	0x0040
+
+typedef u32 phys_addr;
+
+static inline phys_addr
+va_to_pa(volatile void *x) {
+	return x ? virt_to_bus(x) : I596_NULL;
+}
+
+static inline void *
+pa_to_va(phys_addr x) {
+	return (x == I596_NULL) ? NULL : bus_to_virt(x);
+}
+
+/* status bits for cmd */
+#define CMD_STAT_C	0x8000	/* CU command complete */
+#define CMD_STAT_B	0x4000	/* CU command in progress */
+#define CMD_STAT_OK	0x2000	/* CU command completed without errors */
+#define CMD_STAT_A	0x1000	/* CU command abnormally terminated */
+
+struct i596_cmd {		/* 8 bytes */
+	unsigned short status;
+	unsigned short command;
+	phys_addr pa_next;	/* va_to_pa(struct i596_cmd *next) */
+};
+
+#define EOF		0x8000
+#define SIZE_MASK	0x3fff
+
+struct i596_tbd {
+	unsigned short size;
+	unsigned short pad;
+	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */
+	phys_addr pa_data;	/* va_to_pa(char *data) */
+	struct sk_buff *skb;
+};
+
+struct tx_cmd {
+	struct i596_cmd cmd;
+	phys_addr pa_tbd;	/* va_to_pa(struct i596_tbd *tbd) */
+	unsigned short size;
+	unsigned short pad;
+};
+
+/* status bits for rfd */
+#define RFD_STAT_C	0x8000	/* Frame reception complete */
+#define RFD_STAT_B	0x4000	/* Frame reception in progress */
+#define RFD_STAT_OK	0x2000	/* Frame received without errors */
+#define RFD_STATUS	0x1fff
+#define RFD_LENGTH_ERR	0x1000
+#define RFD_CRC_ERR	0x0800
+#define RFD_ALIGN_ERR	0x0400
+#define RFD_NOBUFS_ERR	0x0200
+#define RFD_DMA_ERR	0x0100	/* DMA overrun failure to acquire system bus */
+#define RFD_SHORT_FRAME_ERR	0x0080
+#define RFD_NOEOP_ERR	0x0040
+#define RFD_TRUNC_ERR	0x0020
+#define RFD_MULTICAST  0x0002	/* 0: destination had our address
+				   1: destination was broadcast/multicast */
+#define RFD_COLLISION  0x0001
+
+/* receive frame descriptor */
+struct i596_rfd {
+	unsigned short stat;
+	unsigned short cmd;
+	phys_addr pa_next;	/* va_to_pa(struct i596_rfd *next) */
+	phys_addr pa_rbd;	/* va_to_pa(struct i596_rbd *rbd) */
+	unsigned short count;
+	unsigned short size;
+	char data[1532];
+};
+
+#define RBD_EL		0x8000
+#define RBD_P		0x4000
+#define RBD_SIZEMASK	0x3fff
+#define RBD_EOF		0x8000
+#define RBD_F		0x4000
+
+/* receive buffer descriptor */
+struct i596_rbd {
+	unsigned short size;
+	unsigned short pad;
+	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */
+	phys_addr pa_data;	/* va_to_pa(char *data) */
+	phys_addr pa_prev;	/* va_to_pa(struct i596_tbd *prev) */
+	
+	/* Driver private part */
+	struct sk_buff *skb;
+};
+
+#define RX_RING_SIZE 64
+#define RX_SKBSIZE (ETH_FRAME_LEN+10)
+#define RX_RBD_SIZE 32
+
+/* System Control Block - 40 bytes */
+struct i596_scb {
+	u16 status;		/* 0 */
+	u16 command;		/* 2 */
+	phys_addr pa_cmd;	/* 4 - va_to_pa(struct i596_cmd *cmd) */
+	phys_addr pa_rfd;	/* 8 - va_to_pa(struct i596_rfd *rfd) */
+	u32 crc_err;		/* 12 */
+	u32 align_err;		/* 16 */
+	u32 resource_err;	/* 20 */
+	u32 over_err;		/* 24 */
+	u32 rcvdt_err;		/* 28 */
+	u32 short_err;		/* 32 */
+	u16 t_on;		/* 36 */
+	u16 t_off;		/* 38 */
+};
+
+/* Intermediate System Configuration Pointer - 8 bytes */
+struct i596_iscp {
+	u32 busy;		/* 0 */
+	phys_addr pa_scb;	/* 4 - va_to_pa(struct i596_scb *scb) */
+};
+
+/* System Configuration Pointer - 12 bytes */
+struct i596_scp {
+	u32 sysbus;		/* 0 */
+	u32 pad;		/* 4 */
+	phys_addr pa_iscp;	/* 8 - va_to_pa(struct i596_iscp *iscp) */
+};
+
+/* Selftest and dump results - needs 16-byte alignment */
+/*
+ * The size of the dump area is 304 bytes. When the dump is executed
+ * by the Port command an extra word will be appended to the dump area.
+ * The extra word is a copy of the Dump status word (containing the
+ * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
+ */
+struct i596_dump {
+	u16 dump[153];		/* (304 = 130h) + 2 bytes */
+};
+
+struct i596_private {		/* aligned to a 16-byte boundary */
+	struct i596_scp scp;	/* 0 - needs 16-byte alignment */
+	struct i596_iscp iscp;	/* 12 */
+	struct i596_scb scb;	/* 20 */
+	u32 dummy;		/* 60 */
+	struct i596_dump dump;	/* 64 - needs 16-byte alignment */
+
+	struct i596_cmd set_add;
+	char eth_addr[8];	/* directly follows set_add */
+
+	struct i596_cmd set_conf;
+	char i596_config[16];	/* directly follows set_conf */
+
+	struct i596_cmd tdr;
+	unsigned long tdr_stat;	/* directly follows tdr */
+
+	int last_restart;
+	volatile struct i596_rbd *rbd_list;
+	volatile struct i596_rbd *rbd_tail;
+	volatile struct i596_rfd *rx_tail;
+	volatile struct i596_cmd *cmd_tail;
+	volatile struct i596_cmd *cmd_head;
+	int cmd_backlog;
+	unsigned long last_cmd;
+	struct net_device_stats stats;
+};
+
+static char init_setup[14] = {
+	0x8E,	/* length 14 bytes, prefetch on */
+	0xC8,	/* default: fifo to 8, monitor off */
+	0x40,	/* default: don't save bad frames (apricot.c had 0x80) */
+	0x2E,	/* (default is 0x26)
+		   No source address insertion, 8 byte preamble */
+	0x00,	/* default priority and backoff */
+	0x60,	/* default interframe spacing */
+	0x00,	/* default slot time LSB */
+	0xf2,	/* default slot time and nr of retries */
+	0x00,	/* default various bits
+		   (0: promiscuous mode, 1: broadcast disable,
+		    2: encoding mode, 3: transmit on no CRS,
+		    4: no CRC insertion, 5: CRC type,
+		    6: bit stuffing, 7: padding) */
+	0x00,	/* default carrier sense and collision detect */
+	0x40,	/* default minimum frame length */
+	0xff,	/* (default is 0xff, and that is what apricot.c has;
+		   elp486.c has 0xfb: Enable crc append in memory.) */
+	0x00,	/* default: not full duplex */
+	0x7f	/* (default is 0x3f) multi IA */
+};
+
+static int i596_open(struct net_device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int i596_close(struct net_device *dev);
+static struct net_device_stats *i596_get_stats(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void print_eth(char *);
+static void set_multicast_list(struct net_device *dev);
+static void i596_tx_timeout(struct net_device *dev);
+
+static int
+i596_timeout(struct net_device *dev, char *msg, int ct) {
+	volatile struct i596_private *lp;
+	int boguscnt = ct;
+
+	lp = (struct i596_private *) dev->priv;
+	while (lp->scb.command) {
+		if (--boguscnt == 0) {
+			printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
+			       dev->name, msg,
+			       lp->scb.status, lp->scb.command);
+			return 1;
+		}
+		udelay(5);
+	}
+	return 0;
+}
+
+static inline int
+init_rx_bufs(struct net_device *dev, int num) {
+	volatile struct i596_private *lp;
+	struct i596_rfd *rfd;
+	int i;
+	// struct i596_rbd *rbd;
+
+	lp = (struct i596_private *) dev->priv;
+	lp->scb.pa_rfd = I596_NULL;
+
+	for (i = 0; i < num; i++) {
+		rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
+		if (rfd == NULL)
+			break;
+
+		rfd->stat = 0;
+		rfd->pa_rbd = I596_NULL;
+		rfd->count = 0;
+		rfd->size = 1532;
+		if (i == 0) {
+			rfd->cmd = CMD_EOL;
+			lp->rx_tail = rfd;
+		} else {
+			rfd->cmd = 0;
+		}
+		rfd->pa_next = lp->scb.pa_rfd;
+		lp->scb.pa_rfd = va_to_pa(rfd);
+		lp->rx_tail->pa_next = lp->scb.pa_rfd;
+	}
+
+#if 0
+	for (i = 0; i<RX_RBD_SIZE; i++) {
+		rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
+		if (rbd) {
+			rbd->pad = 0;
+			rbd->count = 0;
+			rbd->skb = dev_alloc_skb(RX_SKB_SIZE);
+			if (!rbd->skb) {
+				printk("dev_alloc_skb failed");
+			}
+			rbd->next = rfd->rbd;
+			if (i) {
+				rfd->rbd->prev = rbd;
+				rbd->size = RX_SKB_SIZE;
+			} else {
+				rbd->size = (RX_SKB_SIZE | RBD_EL);
+				lp->rbd_tail = rbd;
+			}
+
+			rfd->rbd = rbd;
+		} else {
+			printk("Could not kmalloc rbd\n");
+		}
+	}
+	lp->rbd_tail->next = rfd->rbd;
+#endif
+	return (i);
+}
+
+static inline void
+remove_rx_bufs(struct net_device *dev) {
+	struct i596_private *lp;
+	struct i596_rfd *rfd;
+
+	lp = (struct i596_private *) dev->priv;
+	lp->rx_tail->pa_next = I596_NULL;
+
+	do {
+		rfd = pa_to_va(lp->scb.pa_rfd);
+		lp->scb.pa_rfd = rfd->pa_next;
+		kfree(rfd);
+	} while (rfd != lp->rx_tail);
+
+	lp->rx_tail = 0;
+
+#if 0
+	for (lp->rbd_list) {
+	}
+#endif
+}
+
+#define PORT_RESET              0x00    /* reset 82596 */
+#define PORT_SELFTEST           0x01    /* selftest */
+#define PORT_ALTSCP             0x02    /* alternate SCB address */
+#define PORT_DUMP               0x03    /* dump */
+
+#define IOADDR	0xcb0		/* real constant */
+#define IRQ	10		/* default IRQ - can be changed by ECU */
+
+/* The 82596 requires two 16-bit write cycles for a port command */
+static inline void
+PORT(phys_addr a, unsigned int cmd) {
+	if (a & 0xf)
+		printk("lp486e.c: PORT: address not aligned\n");
+	outw(((a & 0xffff) | cmd), IOADDR);
+	outw(((a>>16) & 0xffff), IOADDR+2);
+}
+
+static inline void
+CA(void) {
+	outb(0, IOADDR+4);
+	udelay(8);
+}
+
+static inline void
+CLEAR_INT(void) {
+	outb(0, IOADDR+8);
+}
+
+#define SIZE(x)	(sizeof(x)/sizeof((x)[0]))
+
+#if 0
+/* selftest or dump */
+static void
+i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
+	volatile struct i596_private *lp = dev->priv;
+	volatile u16 *outp;
+	int i, m;
+
+	memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
+	outp = &(lp->dump.dump[0]);
+
+	PORT(va_to_pa(outp), portcmd);
+	mdelay(30);             /* random, unmotivated */
+
+	printk("lp486e i82596 %s result:\n", cmdname);
+	for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+		;
+	for (i = 0; i < m; i++) {
+		printk(" %04x", lp->dump.dump[i]);
+		if (i%8 == 7)
+			printk("\n");
+	}
+	printk("\n");
+}
+#endif
+
+static int
+i596_scp_setup(struct net_device *dev) {
+	volatile struct i596_private *lp = dev->priv;
+	int boguscnt;
+
+	/* Setup SCP, ISCP, SCB */
+	/*
+	 * sysbus bits:
+	 *  only a single byte is significant - here 0x44
+	 *  0x80: big endian mode (details depend on stepping)
+	 *  0x40: 1
+	 *  0x20: interrupt pin is active low
+	 *  0x10: lock function disabled
+	 *  0x08: external triggering of bus throttle timers
+	 *  0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
+	 *  0x01: unused
+	 */
+	lp->scp.sysbus = 0x00440000; 		/* linear mode */
+	lp->scp.pad = 0;			/* must be zero */
+	lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
+
+	/*
+	 * The CPU sets the ISCP to 1 before it gives the first CA()
+	 */
+	lp->iscp.busy = 0x0001;
+	lp->iscp.pa_scb = va_to_pa(&(lp->scb));
+
+	lp->scb.command = 0;
+	lp->scb.status = 0;
+	lp->scb.pa_cmd = I596_NULL;
+	/* lp->scb.pa_rfd has been initialised already */
+
+	lp->last_cmd = jiffies;
+	lp->cmd_backlog = 0;
+	lp->cmd_head = NULL;
+
+	/*
+	 * Reset the 82596.
+	 * We need to wait 10 systemclock cycles, and
+	 * 5 serial clock cycles.
+	 */
+	PORT(0, PORT_RESET);	/* address part ignored */
+	udelay(100);
+
+	/*
+	 * Before the CA signal is asserted, the default SCP address
+	 * (0x00fffff4) can be changed to a 16-byte aligned value
+	 */
+	PORT(va_to_pa(&lp->scp), PORT_ALTSCP);	/* change the scp address */
+
+	/*
+	 * The initialization procedure begins when a
+	 * Channel Attention signal is asserted after a reset.
+	 */
+
+	CA();
+
+	/*
+	 * The ISCP busy is cleared by the 82596 after the SCB address is read.
+	 */
+	boguscnt = 100;
+	while (lp->iscp.busy) {
+		if (--boguscnt == 0) {
+			/* No i82596 present? */
+			printk("%s: i82596 initialization timed out\n",
+			       dev->name);
+			return 1;
+		}
+		udelay(5);
+	}
+	/* I find here boguscnt==100, so no delay was required. */
+
+	return 0;
+}
+
+static int
+init_i596(struct net_device *dev) {
+	volatile struct i596_private *lp;
+
+	if (i596_scp_setup(dev))
+		return 1;
+
+	lp = (struct i596_private *) dev->priv;
+	lp->scb.command = 0;
+
+	memcpy ((void *)lp->i596_config, init_setup, 14);
+	lp->set_conf.command = CmdConfigure;
+	i596_add_cmd(dev, (void *)&lp->set_conf);
+
+	memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
+	lp->set_add.command = CmdIASetup;
+	i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
+
+	lp->tdr.command = CmdTDR;
+	i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
+
+	if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
+		return 1;
+
+	lp->scb.command = RX_START;
+	CA();
+
+	if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
+		return 1;
+
+	return 0;
+}
+
+/* Receive a single frame */
+static inline int
+i596_rx_one(struct net_device *dev, volatile struct i596_private *lp,
+	    struct i596_rfd *rfd, int *frames) {
+
+	if (rfd->stat & RFD_STAT_OK) {
+		/* a good frame */
+		int pkt_len = (rfd->count & 0x3fff);
+		struct sk_buff *skb = dev_alloc_skb(pkt_len);
+
+		(*frames)++;
+
+		if (rfd->cmd & CMD_EOL)
+			printk("Received on EOL\n");
+
+		if (skb == NULL) {
+			printk ("%s: i596_rx Memory squeeze, "
+				"dropping packet.\n", dev->name);
+			lp->stats.rx_dropped++;
+			return 1;
+		}
+
+		skb->dev = dev;		
+		memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
+
+		skb->protocol = eth_type_trans(skb,dev);
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+	} else {
+#if 0
+		printk("Frame reception error status %04x\n",
+		       rfd->stat);
+#endif
+		lp->stats.rx_errors++;
+		if (rfd->stat & RFD_COLLISION)
+			lp->stats.collisions++;
+		if (rfd->stat & RFD_SHORT_FRAME_ERR)
+			lp->stats.rx_length_errors++;
+		if (rfd->stat & RFD_DMA_ERR)
+			lp->stats.rx_over_errors++;
+		if (rfd->stat & RFD_NOBUFS_ERR)
+			lp->stats.rx_fifo_errors++;
+		if (rfd->stat & RFD_ALIGN_ERR)
+			lp->stats.rx_frame_errors++;
+		if (rfd->stat & RFD_CRC_ERR)
+			lp->stats.rx_crc_errors++;
+		if (rfd->stat & RFD_LENGTH_ERR)
+			lp->stats.rx_length_errors++;
+	}
+	rfd->stat = rfd->count = 0;
+	return 0;
+}
+
+static int
+i596_rx(struct net_device *dev) {
+	volatile struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_rfd *rfd;
+	int frames = 0;
+
+	while (1) {
+		rfd = pa_to_va(lp->scb.pa_rfd);
+		if (!rfd) {
+			printk("i596_rx: NULL rfd?\n");
+			return 0;
+		}
+#if 1
+		if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
+			printk("SF:%p-%04x\n", rfd, rfd->stat);
+#endif
+		if (!(rfd->stat & RFD_STAT_C))
+			break;		/* next one not ready */
+		if (i596_rx_one(dev, lp, rfd, &frames))
+			break;		/* out of memory */
+		rfd->cmd = CMD_EOL;
+		lp->rx_tail->cmd = 0;
+		lp->rx_tail = rfd;
+		lp->scb.pa_rfd = rfd->pa_next;
+	}
+
+	return frames;
+}
+
+static void
+i596_cleanup_cmd(struct net_device *dev) {
+	volatile struct i596_private *lp;
+	struct i596_cmd *cmd;
+
+	lp = (struct i596_private *) dev->priv;
+	while (lp->cmd_head) {
+		cmd = (struct i596_cmd *)lp->cmd_head;
+
+		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+		lp->cmd_backlog--;
+
+		switch ((cmd->command) & 0x7) {
+			case CmdTx: {
+				struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
+				struct i596_tbd * tx_cmd_tbd;
+				tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+				dev_kfree_skb_any(tx_cmd_tbd->skb);
+
+				lp->stats.tx_errors++;
+				lp->stats.tx_aborted_errors++;
+
+				cmd->pa_next = I596_NULL;
+				kfree((unsigned char *)tx_cmd);
+				netif_wake_queue(dev);
+				break;
+			}
+			case CmdMulticastList: {
+				// unsigned short count = *((unsigned short *) (ptr + 1));
+
+				cmd->pa_next = I596_NULL;
+				kfree((unsigned char *)cmd);
+				break;
+			}
+			default: {
+				cmd->pa_next = I596_NULL;
+				break;
+			}
+		}
+	}
+
+	if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
+		;
+
+	lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+}
+
+static inline void
+i596_reset(struct net_device *dev,
+	   volatile struct i596_private *lp, int ioaddr) {
+
+	if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
+		;
+
+	netif_stop_queue(dev);
+
+	lp->scb.command = CUC_ABORT | RX_ABORT;
+	CA();
+
+	/* wait for shutdown */
+	if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
+		;
+
+	i596_cleanup_cmd(dev);
+	i596_rx(dev);
+
+	netif_start_queue(dev);
+	/*dev_kfree_skb(skb, FREE_WRITE);*/
+	init_i596(dev);
+}
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
+	volatile struct i596_private *lp = dev->priv;
+	int ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	cmd->status = 0;
+	cmd->command |= (CMD_EOL | CMD_INTR);
+	cmd->pa_next = I596_NULL;
+
+	save_flags(flags);
+	cli();
+	if (lp->cmd_head) {
+		lp->cmd_tail->pa_next = va_to_pa(cmd);
+	} else {
+		lp->cmd_head = cmd;
+		if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
+			;
+		lp->scb.pa_cmd = va_to_pa(cmd);
+		lp->scb.command = CUC_START;
+		CA();
+	}
+	lp->cmd_tail = cmd;
+	lp->cmd_backlog++;
+
+	lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
+	restore_flags(flags);
+
+	if (lp->cmd_backlog > 16) {
+		int tickssofar = jiffies - lp->last_cmd;
+		if (tickssofar < 25) return;
+
+		printk("%s: command unit timed out, status resetting.\n",
+		       dev->name);
+		i596_reset(dev, lp, ioaddr);
+	}
+}
+
+static int
+i596_open(struct net_device *dev) {
+	int i;
+
+	i = request_irq(dev->irq, &i596_interrupt, SA_SHIRQ, dev->name, dev);
+	if (i) {
+		printk("%s: IRQ %d not free\n", dev->name, dev->irq);
+		return i;
+	}
+
+	if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+		printk("%s: only able to allocate %d receive buffers\n",
+		       dev->name, i);
+
+	if (i < 4) {
+// release buffers
+		free_irq(dev->irq, dev);
+		return -EAGAIN;
+	}
+
+	netif_start_queue(dev);
+
+	init_i596(dev);
+
+	return 0;			/* Always succeed */
+}
+
+static int
+i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
+	volatile struct i596_private *lp = dev->priv;
+	struct tx_cmd *tx_cmd;
+	short length;
+
+	/* If some higher level thinks we've missed a tx-done interrupt
+	   we are passed NULL. n.b. dev_tint handles the cli()/sti()
+	   itself. */
+	if (skb == NULL) {
+		printk ("What about dev_tint\n");
+		/* dev_tint(dev); */
+		return 0;
+	}
+
+	/* shouldn't happen */
+	if (skb->len <= 0)
+		return 0;
+
+	length = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	dev->trans_start = jiffies;
+
+	tx_cmd = (struct tx_cmd *)
+	    kmalloc ((sizeof (struct tx_cmd)
+		      + sizeof (struct i596_tbd)), GFP_ATOMIC);
+	if (tx_cmd == NULL) {
+		printk ("%s: i596_xmit Memory squeeze, dropping packet.\n",
+			dev->name);
+		lp->stats.tx_dropped++;
+
+		dev_kfree_skb (skb);
+	} else {
+		struct i596_tbd *tx_cmd_tbd;
+		tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
+		tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
+		tx_cmd_tbd->pa_next = I596_NULL;
+
+		tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
+
+		tx_cmd->pad = 0;
+		tx_cmd->size = 0;
+		tx_cmd_tbd->pad = 0;
+		tx_cmd_tbd->size = (EOF | length);
+
+		tx_cmd_tbd->pa_data = va_to_pa (skb->data);
+		tx_cmd_tbd->skb = skb;
+
+		if (i596_debug & LOG_SRCDST)
+			print_eth (skb->data);
+
+		i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
+
+		lp->stats.tx_packets++;
+	}
+
+	return 0;
+}
+
+static void
+i596_tx_timeout (struct net_device *dev) {
+	volatile struct i596_private *lp = dev->priv;
+	int ioaddr = dev->base_addr;
+
+	/* Transmitter timeout, serious problems. */
+	printk ("%s: transmit timed out, status resetting.\n", dev->name);
+	lp->stats.tx_errors++;
+
+	/* Try to restart the adaptor */
+	if (lp->last_restart == lp->stats.tx_packets) {
+		printk ("Resetting board.\n");
+
+		/* Shutdown and restart */
+		i596_reset (dev, lp, ioaddr);
+	} else {
+		/* Issue a channel attention signal */
+		printk ("Kicking board.\n");
+		lp->scb.command = (CUC_START | RX_START);
+		CA();
+		lp->last_restart = lp->stats.tx_packets;
+	}
+	netif_wake_queue(dev);
+}
+
+static void
+print_eth(char *add) {
+	int i;
+
+	printk ("Dest  ");
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", (unsigned char) add[i]);
+	printk ("\n");
+
+	printk ("Source");
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", (unsigned char) add[i+6]);
+	printk ("\n");
+
+	printk ("type %2.2X%2.2X\n",
+		(unsigned char) add[12], (unsigned char) add[13]);
+}
+
+int __init
+lp486e_probe(struct net_device *dev) {
+	volatile struct i596_private *lp;
+	unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
+	unsigned char *bios;
+	int i, j;
+	int ret = -ENOMEM;
+	static int probed;
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+
+	if (!request_region(IOADDR, LP486E_TOTAL_SIZE, dev->name)) {
+		printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
+		return -EBUSY;
+	}
+
+	/*
+	 * Allocate working memory, 16-byte aligned
+	 */
+	dev->mem_start = (unsigned long)
+		kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL);
+	if (!dev->mem_start)
+		goto err_out;
+	dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0);
+	lp = (struct i596_private *) dev->priv;
+	memset((void *)lp, 0, sizeof(struct i596_private));
+
+	/*
+	 * Do we really have this thing?
+	 */
+	if (i596_scp_setup(dev)) {
+		ret = -ENODEV;
+		goto err_out_kfree;
+	}
+
+	dev->base_addr = IOADDR;
+	dev->irq = IRQ;
+
+	ether_setup(dev);
+
+	/*
+	 * How do we find the ethernet address? I don't know.
+	 * One possibility is to look at the EISA configuration area
+	 * [0xe8000-0xe9fff]. This contains the ethernet address
+	 * but not at a fixed address - things depend on setup options.
+	 *
+	 * If we find no address, or the wrong address, use
+	 *   ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
+	 * with the value found in the BIOS setup.
+	 */
+	bios = bus_to_virt(0xe8000);
+	for (j = 0; j < 0x2000; j++) {
+		if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
+			printk("%s: maybe address at BIOS 0x%x:",
+			       dev->name, 0xe8000+j);
+			for (i = 0; i < 6; i++) {
+				eth_addr[i] = bios[i+j];
+				printk(" %2.2X", eth_addr[i]);
+			}
+			printk("\n");
+		}
+	}
+
+	printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
+	       dev->name, dev->base_addr, dev->irq);
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+	printk("\n");
+
+	/* The LP486E-specific entries in the device structure. */
+	dev->open = &i596_open;
+	dev->stop = &i596_close;
+	dev->hard_start_xmit = &i596_start_xmit;
+	dev->get_stats = &i596_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->watchdog_timeo = 5*HZ;
+	dev->tx_timeout = i596_tx_timeout;
+
+#if 0
+	/* selftest reports 0x320925ae - don't know what that means */
+	i596_port_do(dev, PORT_SELFTEST, "selftest");
+	i596_port_do(dev, PORT_DUMP, "dump");
+#endif
+	return 0;
+
+err_out_kfree:
+	kfree ((void *) dev->mem_start);
+err_out:
+	release_region(IOADDR, LP486E_TOTAL_SIZE);
+	return ret;
+}
+
+static void inline
+i596_handle_CU_completion(struct net_device *dev,
+			  volatile struct i596_private *lp,
+			  unsigned short status,
+			  unsigned short *ack_cmdp) {
+	volatile struct i596_cmd *cmd;
+	int frames_out = 0;
+	int commands_done = 0;
+	int cmd_val;
+
+	cmd = lp->cmd_head;
+
+	while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
+		cmd = lp->cmd_head;
+
+		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+		lp->cmd_backlog--;
+
+		commands_done++;
+		cmd_val = cmd->command & 0x7;
+#if 0
+		printk("finished CU %s command (%d)\n",
+		       CUcmdnames[cmd_val], cmd_val);
+#endif
+		switch (cmd_val) {
+		case CmdTx:
+		{
+			struct tx_cmd *tx_cmd;
+			struct i596_tbd *tx_cmd_tbd;
+
+			tx_cmd = (struct tx_cmd *) cmd;
+			tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+			frames_out++;
+			if (cmd->status & CMD_STAT_OK) {
+				if (i596_debug)
+					print_eth(pa_to_va(tx_cmd_tbd->pa_data));
+			} else {
+				lp->stats.tx_errors++;
+				if (i596_debug)
+					printk("transmission failure:%04x\n",
+					       cmd->status);
+				if (cmd->status & 0x0020)
+					lp->stats.collisions++;
+				if (!(cmd->status & 0x0040))
+					lp->stats.tx_heartbeat_errors++;
+				if (cmd->status & 0x0400)
+					lp->stats.tx_carrier_errors++;
+				if (cmd->status & 0x0800)
+					lp->stats.collisions++;
+				if (cmd->status & 0x1000)
+					lp->stats.tx_aborted_errors++;
+			}
+			dev_kfree_skb_irq(tx_cmd_tbd->skb);
+
+			cmd->pa_next = I596_NULL;
+			kfree((unsigned char *)tx_cmd);
+			netif_wake_queue(dev);
+			break;
+		}
+
+		case CmdMulticastList:
+			cmd->pa_next = I596_NULL;
+			kfree((unsigned char *)cmd);
+			break;
+
+		case CmdTDR:
+		{
+			unsigned long status = *((unsigned long *) (cmd + 1));
+			if (status & 0x8000) {
+				if (i596_debug)
+					printk("%s: link ok.\n", dev->name);
+			} else {
+				if (status & 0x4000)
+					printk("%s: Transceiver problem.\n",
+					       dev->name);
+				if (status & 0x2000)
+					printk("%s: Termination problem.\n",
+					       dev->name);
+				if (status & 0x1000)
+					printk("%s: Short circuit.\n",
+					       dev->name);
+				printk("%s: Time %ld.\n",
+				       dev->name, status & 0x07ff);
+			}
+		}
+		default:
+			cmd->pa_next = I596_NULL;
+			lp->last_cmd = jiffies;
+			
+		}
+	}
+
+	cmd = lp->cmd_head;
+	while (cmd && (cmd != lp->cmd_tail)) {
+		cmd->command &= 0x1fff;
+		cmd = pa_to_va(cmd->pa_next);
+	}
+
+	if (lp->cmd_head)
+		*ack_cmdp |= CUC_START;
+	lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+}
+
+static void
+i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) {
+	struct net_device *dev = (struct net_device *) dev_instance;
+	volatile struct i596_private *lp;
+	unsigned short status, ack_cmd = 0;
+	int frames_in = 0;
+
+	if (dev == NULL) {
+		printk ("i596_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	lp = (struct i596_private *) dev->priv;
+
+	/*
+	 * The 82596 examines the command, performs the required action,
+	 * and then clears the SCB command word.
+	 */
+	if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
+		;
+
+	/*
+	 * The status word indicates the status of the 82596.
+	 * It is modified only by the 82596.
+	 *
+	 * [So, we must not clear it. I find often status 0xffff,
+	 *  which is not one of the values allowed by the docs.]
+	 */
+	status = lp->scb.status;
+#if 0
+	if (i596_debug) {
+		printk("%s: i596 interrupt, ", dev->name);
+		i596_out_status(status);
+	}
+#endif
+	/* Impossible, but it happens - perhaps when we get
+	   a receive interrupt but scb.pa_rfd is I596_NULL. */
+	if (status == 0xffff) {
+		printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
+		goto out;
+	}
+
+	ack_cmd = (status & STAT_ACK);
+
+	if (status & (STAT_CX | STAT_CNA))
+		i596_handle_CU_completion(dev, lp, status, &ack_cmd);
+
+	if (status & (STAT_FR | STAT_RNR)) {
+		/* Restart the receive unit when it got inactive somehow */
+		if ((status & STAT_RNR) && netif_running(dev))
+			ack_cmd |= RX_START;
+
+		if (status & STAT_FR) {
+			frames_in = i596_rx(dev);
+			if (!frames_in)
+				printk("receive frame reported, but no frames\n");
+		}
+	}
+
+	/* acknowledge the interrupt */
+	/*
+	if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
+		ack_cmd |= CUC_START;
+	*/
+
+	if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
+		;
+
+	lp->scb.command = ack_cmd;
+
+	CLEAR_INT();
+	CA();
+
+ out:
+	return;
+}
+
+static int i596_close(struct net_device *dev) {
+	volatile struct i596_private *lp = dev->priv;
+
+	netif_stop_queue(dev);
+
+	if (i596_debug)
+		printk("%s: Shutting down ethercard, status was %4.4x.\n",
+		       dev->name, lp->scb.status);
+
+	lp->scb.command = (CUC_ABORT | RX_ABORT);
+	CA();
+
+	i596_cleanup_cmd(dev);
+
+	if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
+		;
+
+	free_irq(dev->irq, dev);
+	remove_rx_bufs(dev);
+
+	return 0;
+}
+
+static struct net_device_stats * i596_get_stats(struct net_device *dev) {
+	struct i596_private *lp = dev->priv;
+
+	return &lp->stats;
+}
+
+/*
+*	Set or clear the multicast filter for this adaptor.
+*/
+
+static void set_multicast_list(struct net_device *dev) {
+	volatile struct i596_private *lp = dev->priv;
+	struct i596_cmd *cmd;
+
+	if (i596_debug > 1)
+		printk ("%s: set multicast list %d\n",
+			dev->name, dev->mc_count);
+
+	if (dev->mc_count > 0) {
+		struct dev_mc_list *dmi;
+		char *cp;
+		cmd = (struct i596_cmd *)
+			kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6,
+				GFP_ATOMIC);
+		if (cmd == NULL) {
+			printk ("%s: set_multicast Memory squeeze.\n",
+				dev->name);
+			return;
+		}
+		cmd->command = CmdMulticastList;
+		*((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
+		cp = ((char *)(cmd + 1))+2;
+		for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+			memcpy(cp, dmi,6);
+			cp += 6;
+		}
+		if (i596_debug & LOG_SRCDST)
+			print_eth (((char *)(cmd + 1)) + 2);
+		i596_add_cmd(dev, cmd);
+	} else {
+		if (lp->set_conf.pa_next != I596_NULL) {
+			return;
+		}
+		if (dev->mc_count == 0 &&
+		    !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+			if (dev->flags & IFF_ALLMULTI)
+				dev->flags |= IFF_PROMISC;
+			lp->i596_config[8] &= ~0x01;
+		} else {
+			lp->i596_config[8] |= 0x01;
+		}
+
+		i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
+	}
+}
+
+MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
+MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
+MODULE_PARM(debug, "i");
+//MODULE_PARM(max_interrupt_work, "i");
+//MODULE_PARM(reverse_probe, "i");
+//MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+static struct net_device dev_lp486e;
+static int full_duplex;
+static int options;
+static int io = IOADDR;
+static int irq = IRQ;
+
+static int __init lp486e_init_module(void) {
+	struct net_device *dev = &dev_lp486e;
+	dev->irq = irq;
+	dev->base_addr = io;
+	dev->init = lp486e_probe;
+	if (register_netdev(dev) != 0)
+		return -EIO;
+	full_duplex = 0;
+	options = 0;
+	return 0;
+}
+
+static void __exit lp486e_cleanup_module(void) {
+	unregister_netdev(&dev_lp486e);
+	kfree((void *)dev_lp486e.mem_start);
+	dev_lp486e.priv = NULL;
+	release_region(dev_lp486e.base_addr, LP486E_TOTAL_SIZE);
+}
+
+module_init(lp486e_init_module);
+module_exit(lp486e_cleanup_module);
diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- v2.4.6/linux/drivers/net/pcmcia/ibmtr_cs.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Wed Jul  4 11:50:39 2001
@@ -25,20 +25,9 @@
     All we do here is set the card up enough so that the real ibmtr.c
     driver can find it and work with it properly.
 
-    i.e. We set up the io port, irq, mmio memory and shared ram memory.
-    This enables ibmtr_probe in ibmtr.c to find the card and configure it
-    as though it was a normal ISA and/or PnP card.
-
-    There is some confusion with the difference between available shared
-    ram and the amount actually reserved from memory.  ibmtr.c sets up
-    several offsets depending upon the actual on-board memory, not the
-    reserved memory.  We need to get around this to allow the cards to 
-    work with other cards in restricted memory space.  Therefore the 
-    pcmcia_reality_check function.
-
-    TODO
-	- Write the suspend / resume functions. 
-	- Fix Kernel Oops when removing card before ifconfig down
+    i.e. We set up the io port, irq, mmio memory and shared ram
+    memory.  This enables ibmtr_probe in ibmtr.c to find the card and
+    configure it as though it was a normal ISA and/or PnP card.
 
     CHANGES
 
@@ -49,16 +38,20 @@
     Updated to version 2.2.7 to match the first version of the kernel
     that the modification to ibmtr.c were incorporated into.
     
+    v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com)
+    Address translation feature of PCMCIA controller is usable so
+    memory windows can be placed in High memory (meaning above
+    0xFFFFF.)
+
 ======================================================================*/
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/timer.h>
-#include <linux/delay.h>
 #include <linux/module.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -81,8 +74,9 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n"
-"           2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" ;
+"ibmtr_cs.c 1.10   1996/01/06 05:19:00 (Steve Kipisz)\n"
+"           2.2.7  1999/05/03 12:00:00 (Mike Phillips)\n"
+"           2.4.2  2001/30/28 Midnight (Burt Silverman)\n";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -96,13 +90,13 @@
 static int irq_list[4] = { -1 };
 
 /* MMIO base address */
-static u_long mmiobase;
+static u_long mmiobase = 0xce000;
 
 /* SRAM base address */
-static u_long srambase;
+static u_long srambase = 0xd0000;
 
 /* SRAM size 8,16,32,64 */
-static u_long sramsize = 16;
+static u_long sramsize = 64;
 
 /* Ringspeed 4,16 */
 static int ringspeed = 16;
@@ -117,7 +111,7 @@
 /*====================================================================*/
 
 static void ibmtr_config(dev_link_t *link);
-static void ibmtr_hw_setup(struct net_device *dev);
+static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
 static void ibmtr_release(u_long arg);
 static int ibmtr_event(event_t event, int priority,
                        event_callback_args_t *args);
@@ -130,18 +124,14 @@
 static dev_link_t *dev_list;
 
 extern int ibmtr_probe(struct net_device *dev);
-unsigned char pcmcia_reality_check(unsigned char gss);
-
 extern int trdev_init(struct net_device *dev);
 extern void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-extern int tok_init_card(struct net_device *dev);
-extern unsigned char get_sram_size(struct tok_info *ti);
 
 /*====================================================================*/
 
 typedef struct ibmtr_dev_t {
     dev_link_t		link;
-    struct net_device	*dev; /* Changed for 2.2.0 */
+    struct net_device	*dev;
     dev_node_t          node;
     window_handle_t     sram_win_handle;
     struct tok_info	ti;
@@ -217,14 +207,13 @@
     link->conf.Present = PRESENT_OPTION;
 
     dev = init_trdev(NULL,0);
-    dev->priv = &info->ti;
-    link->irq.Instance = info->dev = dev;
-    
     if (dev == NULL) {
 	ibmtr_detach(link);
         return NULL;
     }
-
+    dev->priv = &info->ti;
+    link->irq.Instance = info->dev = dev;
+    
     dev->init = &ibmtr_probe;
 
     /* Register with Card Services */
@@ -262,7 +251,7 @@
 {
     struct ibmtr_dev_t *info = link->priv;
     dev_link_t **linkp;
-    struct net_device *dev; 
+    struct net_device *dev;
 
     DEBUG(0, "ibmtr_detach(0x%p)\n", link);
 
@@ -291,8 +280,10 @@
 
     /* Unlink device structure, free bits */
     *linkp = link->next;
-    if (link->dev)
+    if (info->dev) {
 	unregister_trdev(info->dev);
+	kfree(info->dev);
+    }
     kfree(info);
 
 } /* ibmtr_detach */
@@ -320,7 +311,6 @@
     memreq_t mem;
     int i, last_ret, last_fn;
     u_char buf[64];
-    unsigned char Shared_Ram_Base;
 
     DEBUG(0, "ibmtr_config(0x%p)\n", link);
 
@@ -361,41 +351,40 @@
 
     /* Allocate the MMIO memory window */
     req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    req.Attributes |= WIN_USE_WAIT|WIN_STRICT_ALIGN;
-    req.Base = mmiobase;
+    req.Attributes |= WIN_USE_WAIT;
+    req.Base = 0; 
     req.Size = 0x2000;
     req.AccessSpeed = 250;
     link->win = (window_handle_t)link->handle;
     CS_CHECK(RequestWindow, &link->win, &req);
 
-    mem.CardOffset = req.Base;
+    mem.CardOffset = mmiobase;
     mem.Page = 0;
     CS_CHECK(MapMemPage, link->win, &mem);
     ti->mmio = (u_long)ioremap(req.Base, req.Size);
 
     /* Allocate the SRAM memory window */
     req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    req.Attributes |= WIN_USE_WAIT|WIN_MAP_BELOW_1MB;
-    req.Base = srambase;
+    req.Attributes |= WIN_USE_WAIT;
+    req.Base = 0;
     req.Size = sramsize * 1024;
     req.AccessSpeed = 250;
     info->sram_win_handle = (window_handle_t)link->handle;
     CS_CHECK(RequestWindow, &info->sram_win_handle, &req);
 
-    mem.CardOffset = req.Base;
+    mem.CardOffset = srambase;
     mem.Page = 0;
     CS_CHECK(MapMemPage, info->sram_win_handle, &mem);
-    Shared_Ram_Base = req.Base >> 12;
-   
-    ti->sram = 0;
-    ti->sram_base = Shared_Ram_Base;
-    
+
+    ti->sram_base = mem.CardOffset >> 12;
+    ti->sram_virt = (u_long)ioremap(req.Base, req.Size);
+
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
 
     /*  Set up the Token-Ring Controller Configuration Register and
         turn on the card.  Check the "Local Area Network Credit Card
         Adapters Technical Reference"  SC30-3585 for this info.  */
-    ibmtr_hw_setup(dev);
+    ibmtr_hw_setup(dev, mmiobase);
 
     i = register_trdev(dev);
     
@@ -477,18 +466,20 @@
     struct net_device *dev = info->dev;
 
     DEBUG(1, "ibmtr_event(0x%06x)\n", event);
-    
+
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
         link->state &= ~DEV_PRESENT;
         if (link->state & DEV_CONFIG) {
+	    /* set flag to bypass normal interrupt code */
+	    ((struct tok_info *)dev->priv)->sram_virt |= 1;
 	    netif_device_detach(dev);
 	    mod_timer(&link->release, jiffies + HZ/20);
         }
         break;
     case CS_EVENT_CARD_INSERTION:
         link->state |= DEV_PRESENT;
-	ibmtr_config(link); 
+	ibmtr_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
         link->state |= DEV_SUSPEND;
@@ -518,10 +509,9 @@
 
 /*====================================================================*/
 
-static void ibmtr_hw_setup(struct net_device *dev)
+static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
 {
-    struct tok_info *ti = dev->priv;
-    int i; 
+    int i;
 
     /* Bizarre IBM behavior, there are 16 bits of information we
        need to set, but the card only allows us to send 4 bits at a 
@@ -530,11 +520,11 @@
        the actual information */
 
     /* First nibble provides 4 bits of mmio */
-    i = ((int)ti->mmio >> 16) & 0x0F;
+    i = (mmiobase >> 16) & 0x0F;
     outb(i, dev->base_addr);
 
     /* Second nibble provides 3 bits of mmio */
-    i = 0x10 | (((int)ti->mmio >> 12) & 0x0E);
+    i = 0x10 | ((mmiobase >> 12) & 0x0E);
     outb(i, dev->base_addr);
 
     /* Third nibble, hard-coded values */
@@ -544,8 +534,7 @@
     /* Fourth nibble sets shared ram page size */
 
     /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */          
-        
-    i = (sramsize >> 4) & 0x07; 
+    i = (sramsize >> 4) & 0x07;
     i = ((i == 4) ? 3 : i) << 2;
     i |= 0x30;
 
@@ -555,28 +544,10 @@
 	i |= 1;
     outb(i, dev->base_addr);
 
-    /* X40 will release the card for use */
-
+    /* 0x40 will release the card for use */
     outb(0x40, dev->base_addr);
-    
-    return;
-}
 
-/*======================================================================
-  
-    A sweet little function that circumvents the problem with
-    ibmtr.c trying to use more memory than we can allocate for
-    the PCMCIA card.  ibmtr.c just assumes that if a card has 
-    64K of shared ram, the entire 64K must be mapped into memory,
-    whereas resources are sometimes a little tight in card services
-    so we fool ibmtr.c into thinking the card has less memory on
-    it than it has.
-    
-======================================================================*/
-
-unsigned char pcmcia_reality_check(unsigned char gss)
-{
-    return (gss < sramsize) ? sramsize : gss;
+    return;
 }
 
 /*====================================================================*/
@@ -584,7 +555,7 @@
 static int __init init_ibmtr_cs(void)
 {
     servinfo_t serv;
-    DEBUG(0, "%s\n", version);
+    DEBUG(0, "%s", version);
     CardServices(GetCardServicesInfo, &serv);
     if (serv.Revision != CS_RELEASE_CODE) {
         printk(KERN_NOTICE "ibmtr_cs: Card Services release "
diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.4.6/linux/drivers/net/ppp_async.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/ppp_async.c	Wed Jul  4 11:50:39 2001
@@ -96,7 +96,7 @@
 static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
 			   int len, int inbound);
 
-struct ppp_channel_ops async_ops = {
+static struct ppp_channel_ops async_ops = {
 	ppp_async_send,
 	ppp_async_ioctl
 };
@@ -308,7 +308,7 @@
 	write_wakeup: ppp_asynctty_wakeup,
 };
 
-int
+static int __init
 ppp_async_init(void)
 {
 	int err;
diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_deflate.c linux/drivers/net/ppp_deflate.c
--- v2.4.6/linux/drivers/net/ppp_deflate.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/ppp_deflate.c	Wed Jul  4 11:50:39 2001
@@ -598,7 +598,7 @@
  * Module interface table
  *************************************************************/
 
-/* These are in ppp.c */
+/* These are in ppp_generic.c */
 extern int  ppp_register_compressor   (struct compressor *cp);
 extern void ppp_unregister_compressor (struct compressor *cp);
 
@@ -639,7 +639,7 @@
 	z_comp_stats,		/* decomp_stat */
 };
 
-int deflate_init(void)
+int __init deflate_init(void)
 {  
         int answer = ppp_register_compressor(&ppp_deflate);
         if (answer == 0)
@@ -649,7 +649,7 @@
         return answer;
 }
      
-void deflate_cleanup(void)
+void __exit deflate_cleanup(void)
 {
 	ppp_unregister_compressor(&ppp_deflate);
 	ppp_unregister_compressor(&ppp_deflate_draft);
diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.4.6/linux/drivers/net/ppp_generic.c	Sun Apr 22 09:46:40 2001
+++ linux/drivers/net/ppp_generic.c	Wed Jul  4 11:50:39 2001
@@ -878,7 +878,7 @@
 	return err;
 }
 
-int
+static int
 ppp_net_init(struct net_device *dev)
 {
 	dev->hard_header_len = PPP_HDRLEN;
diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c
--- v2.4.6/linux/drivers/net/ppp_synctty.c	Fri Apr 20 11:54:24 2001
+++ linux/drivers/net/ppp_synctty.c	Wed Jul  4 11:50:39 2001
@@ -96,7 +96,7 @@
 static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
 			   char *flags, int count);
 
-struct ppp_channel_ops sync_ops = {
+static struct ppp_channel_ops sync_ops = {
 	ppp_sync_send,
 	ppp_sync_ioctl
 };
@@ -365,7 +365,7 @@
 	write_wakeup: ppp_sync_wakeup,
 };
 
-int
+static int __init
 ppp_sync_init(void)
 {
 	int err;
diff -u --recursive --new-file v2.4.6/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c
--- v2.4.6/linux/drivers/net/pppoe.c	Wed May 16 10:31:27 2001
+++ linux/drivers/net/pppoe.c	Wed Jul  4 11:50:39 2001
@@ -410,23 +410,14 @@
 	return 0;
 }
 
-
-
-
 struct packet_type pppoes_ptype = {
-	__constant_htons(ETH_P_PPP_SES),
-	NULL,
-	pppoe_rcv,
-	NULL,
-	NULL
+	type:	__constant_htons(ETH_P_PPP_SES),
+	func:	pppoe_rcv,
 };
 
 struct packet_type pppoed_ptype = {
-	__constant_htons(ETH_P_PPP_DISC),
-	NULL,
-	pppoe_disc_rcv,
-	NULL,
-	NULL
+	type:	__constant_htons(ETH_P_PPP_DISC),
+	func:	pppoe_disc_rcv,
 };
 
 /***********************************************************************
diff -u --recursive --new-file v2.4.6/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c
--- v2.4.6/linux/drivers/net/rrunner.c	Wed Apr 18 14:40:04 2001
+++ linux/drivers/net/rrunner.c	Wed Jul  4 11:50:39 2001
@@ -117,6 +117,14 @@
 
 static int probed __initdata = 0;
 
+#if LINUX_VERSION_CODE >= 0x20400
+static struct pci_device_id rrunner_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, rrunner_pci_tbl);
+#endif /* LINUX_VERSION_CODE >= 0x20400 */
+
 #ifdef NEW_NETINIT
 int __init rr_hippi_probe (void)
 #else
@@ -137,9 +145,6 @@
 		return -ENODEV;
 	probed++;
 
-	if (!pci_present())		/* is PCI BIOS even present? */
-		return -ENODEV;
-
 	version_disp = 0;
 
 	while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL,
@@ -176,6 +181,7 @@
 		sprintf(rrpriv->name, "RoadRunner serial HIPPI");
 
 		dev->irq = pdev->irq;
+		SET_MODULE_OWNER(dev);
 		dev->open = &rr_open;
 		dev->hard_start_xmit = &rr_start_xmit;
 		dev->stop = &rr_close;
@@ -1183,7 +1189,6 @@
 
 	netif_start_queue(dev);
 
-	MOD_INC_USE_COUNT;
 	return ecode;
 
  error:
@@ -1348,7 +1353,6 @@
 	free_irq(dev->irq, dev);
 	spin_unlock(&rrpriv->lock);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/setup.c linux/drivers/net/setup.c
--- v2.4.6/linux/drivers/net/setup.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/setup.c	Wed Jul  4 14:41:33 2001
@@ -10,7 +10,6 @@
 #include <linux/netlink.h>
 
 extern int slip_init_ctrl_dev(void);
-extern int strip_init_ctrl_dev(void);
 extern int x25_asy_init_ctrl_dev(void);
   
 extern int dmascc_init(void);
@@ -23,13 +22,13 @@
 extern int scc_enet_init(void); 
 extern int fec_enet_init(void); 
 extern int dlci_setup(void); 
-extern int lapbeth_init(void);
 extern int sdla_setup(void); 
 extern int sdla_c_setup(void); 
 extern int comx_init(void);
 extern int lmc_setup(void);
 
 extern int madgemc_probe(void);
+extern int uml_net_probe(void);
 
 /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
 #define __PAD6 "\0\0\0\0\0\0\0\0\0"
@@ -64,9 +63,6 @@
 #if defined(CONFIG_SDLA)
 	{sdla_c_setup, 0},
 #endif
-#if defined(CONFIG_LAPBETHER)
-	{lapbeth_init, 0},
-#endif
 #if defined(CONFIG_ARCNET)
 	{arcnet_init, 0},
 #endif
@@ -107,6 +103,10 @@
 #ifdef CONFIG_MADGEMC
 	{madgemc_probe, 0},
 #endif
+#ifdef CONFIG_UML_NET
+	{uml_net_probe, 0},
+#endif
+ 
 	{NULL, 0},
 };
 
@@ -139,9 +139,6 @@
 #endif
 #if defined(CONFIG_X25_ASY)
 	x25_asy_init_ctrl_dev();
-#endif
-#if defined(CONFIG_STRIP)
-	strip_init_ctrl_dev();
 #endif
 }
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/Makefile linux/drivers/net/sk98lin/Makefile
--- v2.4.6/linux/drivers/net/sk98lin/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/sk98lin/Makefile	Wed Jul  4 11:50:39 2001
@@ -7,7 +7,7 @@
 
 obj-y :=     skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \
              ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \
-             skxmac2.o skcsum.o
+             skxmac2.o skproc.o skcsum.o
 obj-m := $(O_TARGET)
 
 # DBGDEF =  \
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/lm80.h linux/drivers/net/sk98lin/h/lm80.h
--- v2.4.6/linux/drivers/net/sk98lin/h/lm80.h	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/h/lm80.h	Wed Jul  4 11:50:39 2001
@@ -126,7 +126,7 @@
 #define LM80_IS_BTI		(1<<1)	/* state of BTI# pin */
 #define LM80_IS_FAN1		(1<<2)	/* count limit exceeded for Fan 1 */
 #define LM80_IS_FAN2		(1<<3)	/* count limit exceeded for Fan 2 */
-#define LM80_IS_CI		(1<<4)	/* Chassis Intrusion occurred */
+#define LM80_IS_CI		(1<<4)	/* Chassis Intrusion occured */
 #define LM80_IS_OS		(1<<5)	/* OS temperature limit exceeded */
 	/* bit 6 and 7 are reserved in LM80_ISRC_2 */
 #define LM80_IS_HT_IRQ_MD	(1<<6)	/* Hot temperature interrupt mode */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skaddr.h linux/drivers/net/sk98lin/h/skaddr.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skaddr.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skaddr.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skaddr.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.23 $
- * Date:	$Date: 2000/08/10 11:27:50 $
+ * Version:	$Revision: 1.24 $
+ * Date:	$Date: 2001/01/22 13:41:34 $
  * Purpose:	Header file for Address Management (MC, UC, Prom).
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,9 @@
  * History:
  *
  *	$Log: skaddr.h,v $
+ *	Revision 1.24  2001/01/22 13:41:34  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
  *	Revision 1.23  2000/08/10 11:27:50  rassmann
  *	Editorial changes.
  *	Preserving 32-bit alignment in structs for the adapter context.
@@ -158,6 +160,8 @@
 #define SK_ADDR_LOGICAL_ADDRESS		0
 #define SK_ADDR_VIRTUAL_ADDRESS		(SK_ADDR_LOGICAL_ADDRESS)	/* old */
 #define SK_ADDR_PHYSICAL_ADDRESS	1
+#define SK_ADDR_CLEAR_LOGICAL		2
+#define SK_ADDR_SET_LOGICAL			4
 
 /* ----- Override return values ----- */
 
@@ -195,18 +199,22 @@
 /* Macros */
 
 #ifndef SK_ADDR_EQUAL
+/*
+ * "&" instead of "&&" allows better optimization on IA-64.
+ * The replacement is safe here, as all bytes exist.
+ */
 #ifndef SK_ADDR_DWORD_COMPARE
 #define SK_ADDR_EQUAL(A1,A2)	( \
-	((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5] && \
-	((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4] && \
-	((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3] && \
-	((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2] && \
-	((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1] && \
-	((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0])
+	(((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \
+	(((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \
+	(((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \
+	(((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \
+	(((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \
+	(((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]))
 #else	/* SK_ADDR_DWORD_COMPARE */
 #define SK_ADDR_EQUAL(A1,A2)	( \
-	*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2]) && \
-	*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0]))
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
 #endif	/* SK_ADDR_DWORD_COMPARE */
 #endif	/* SK_ADDR_EQUAL */
 
@@ -216,25 +224,31 @@
 	SK_U8	a[SK_MAC_ADDR_LEN];
 } SK_MAC_ADDR;
 
+
 /* SK_FILTER is used to ensure alignment of the filter. */
 typedef union s_InexactFilter {
 	SK_U8	Bytes[8];
 	SK_U64	Val;	/* Dummy entry for alignment only. */
 } SK_FILTER64;
 
+
+typedef struct s_AddrNet SK_ADDR_NET;
+
+
 typedef struct s_AddrPort {
 
 /* ----- Public part (read-only) ----- */
 
 	SK_MAC_ADDR	CurrentMacAddress;		/* Current physical MAC Address. */
 	SK_MAC_ADDR	PermanentMacAddress;	/* Permanent physical MAC Address. */
-	int		PromMode;					/* Promiscuous Mode. */
+	int			PromMode;				/* Promiscuous Mode. */
 
 /* ----- Private part ----- */
 
 	SK_MAC_ADDR	PreviousMacAddress;		/* Prev. phys. MAC Address. */
 	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
 	SK_U8		Align01;
+
 	SK_U32		FirstExactMatchRlmt;
 	SK_U32		NextExactMatchRlmt;
 	SK_U32		FirstExactMatchDrv;
@@ -243,20 +257,30 @@
 	SK_FILTER64	InexactFilter;			/* For 64-bit hash register. */
 } SK_ADDR_PORT;
 
+
+struct s_AddrNet {
+/* ----- Public part (read-only) ----- */
+
+	SK_MAC_ADDR		CurrentMacAddress;		/* Logical MAC Address. */
+	SK_MAC_ADDR		PermanentMacAddress;	/* Logical MAC Address. */
+
+/* ----- Private part ----- */
+
+	SK_U32			ActivePort;				/* View of module ADDR. */
+	SK_BOOL			CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_U8			Align01;
+	SK_U16			Align02;
+};
+
+
 typedef struct s_Addr {
 
 /* ----- Public part (read-only) ----- */
 
+	SK_ADDR_NET		Net[SK_MAX_NETS];
 	SK_ADDR_PORT	Port[SK_MAX_MACS];
-	SK_MAC_ADDR	PermanentMacAddress;	/* Logical MAC Address. */
-	SK_MAC_ADDR	CurrentMacAddress;		/* Logical MAC Address. */
 
 /* ----- Private part ----- */
-
-	SK_U32		ActivePort;				/* View of module ADDR. */
-	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
-	SK_U8		Align01;
-	SK_U16		Align02;
 } SK_ADDR;
 
 /* function prototypes ********************************************************/
@@ -270,44 +294,44 @@
 extern	int	SkAddrInit(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	int	Level);
+	int		Level);
 
 extern	int	SkAddrMcClear(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	SK_U32	PortIdx,
-	int	Flags);
+	SK_U32	PortNumber,
+	int		Flags);
 
 extern	int	SkAddrMcAdd(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
-	SK_U32		PortIdx,
+	SK_U32		PortNumber,
 	SK_MAC_ADDR	*pMc,
-	int		Flags);
+	int			Flags);
 
 extern	int	SkAddrMcUpdate(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	SK_U32	PortIdx);
+	SK_U32	PortNumber);
 
 extern	int	SkAddrOverride(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
-	SK_U32		PortIdx,
+	SK_U32		PortNumber,
 	SK_MAC_ADDR	*pNewAddr,
-	int		Flags);
+	int			Flags);
 
 extern	int	SkAddrPromiscuousChange(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	SK_U32	PortIdx,
-	int	NewPromMode);
+	SK_U32	PortNumber,
+	int		NewPromMode);
 
 extern	int	SkAddrSwap(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	SK_U32	FromPortIdx,
-	SK_U32	ToPortIdx);
+	SK_U32	FromPortNumber,
+	SK_U32	ToPortNumber);
 
 #else	/* defined(SK_KR_PROTO)) */
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skcsum.h linux/drivers/net/sk98lin/h/skcsum.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skcsum.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skcsum.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skcsum.h
  * Project:	GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
- * Version:	$Revision: 1.7 $
- * Date:	$Date: 2000/06/29 13:17:05 $
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 2001/02/06 11:21:39 $
  * Purpose:	Store/verify Internet checksum in send/receive packets.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,12 @@
  * History:
  *
  *	$Log: skcsum.h,v $
+ *	Revision 1.9  2001/02/06 11:21:39  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.8  2001/02/06 11:15:36  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
  *	Revision 1.7  2000/06/29 13:17:05  rassmann
  *	Corrected reception of a packet with UDP checksum == 0 (which means there
  *	is no UDP checksum).
@@ -193,13 +198,13 @@
  */
 typedef struct s_Csum {
 	/* Enabled receive SK_PROTO_XXX bit flags. */
-	unsigned ReceiveFlags;
+	unsigned ReceiveFlags[SK_MAX_NETS];
 #ifdef TX_CSUM
-	unsigned TransmitFlags;
+	unsigned TransmitFlags[SK_MAX_NETS];
 #endif /* TX_CSUM */
 
 	/* The protocol statistics structure; one per supported protocol. */
-	SKCS_PROTO_STATS ProtoStats[SKCS_NUM_PROTOCOLS];
+	SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS];
 } SK_CSUM;
 
 /*
@@ -237,17 +242,20 @@
 	SK_AC		*pAc,
 	void		*pIpHeader,
 	unsigned	Checksum1,
-	unsigned	Checksum2);
+	unsigned	Checksum2,
+	int			NetNumber);
 
 extern void SkCsGetSendInfo(
-	SK_AC			*pAc,
-	void			*pIpHeader,
-	SKCS_PACKET_INFO	*pPacketInfo);
+	SK_AC				*pAc,
+	void				*pIpHeader,
+	SKCS_PACKET_INFO	*pPacketInfo,
+	int					NetNumber);
 
 extern void SkCsSetReceiveFlags(
 	SK_AC		*pAc,
 	unsigned	ReceiveFlags,
 	unsigned	*pChecksum1Offset,
-	unsigned	*pChecksum2Offset);
+	unsigned	*pChecksum2Offset,
+	int			NetNumber);
 
 #endif	/* __INC_SKCSUM_H */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skdrv1st.h linux/drivers/net/sk98lin/h/skdrv1st.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skdrv1st.h	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/sk98lin/h/skdrv1st.h	Wed Jul  4 11:50:39 2001
@@ -2,15 +2,15 @@
  *
  * Name:	skdrv1st.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.8 $
- * Date:	$Date: 2000/02/21 12:19:18 $
+ * Version:	$Revision: 1.9.2.1 $
+ * Date:	$Date: 2001/03/12 16:50:59 $
  * Purpose:	First header file for driver and all other modules
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1998-2001 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,14 @@
  * History:
  *
  *	$Log: skdrv1st.h,v $
+ *	Revision 1.9.2.1  2001/03/12 16:50:59  mlindner
+ *	chg: kernel 2.4 adaption
+ *	
+ *	Revision 1.9  2001/01/22 14:16:04  mlindner
+ *	added ProcFs functionality
+ *	Dual Net functionality integrated
+ *	Rlmt networks added
+ *	
  *	Revision 1.8  2000/02/21 12:19:18  cgoos
  *	Added default for SK_DEBUG_CHKMOD/_CHKCAT
  *	
@@ -105,7 +113,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <asm/byteorder.h>
@@ -140,6 +148,7 @@
 // #define SK_RLMT_SLOW_LOOKAHEAD
 
 #define SK_MAX_MACS		2
+#define SK_MAX_NETS		2
 
 #define SK_IOC			char*
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skdrv2nd.h linux/drivers/net/sk98lin/h/skdrv2nd.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skdrv2nd.h	Tue Feb  8 18:58:25 2000
+++ linux/drivers/net/sk98lin/h/skdrv2nd.h	Wed Jul  4 11:50:39 2001
@@ -2,15 +2,15 @@
  *
  * Name:	skdrv2nd.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.7 $
- * Date:	$Date: 1999/09/28 12:38:21 $
+ * Version:	$Revision: 1.12.2.1 $
+ * Date:	$Date: 2001/03/12 16:50:59 $
  * Purpose:	Second header file for driver and all other modules
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1998-2001 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,32 @@
  * History:
  *
  *	$Log: skdrv2nd.h,v $
+ *	Revision 1.12.2.1  2001/03/12 16:50:59  mlindner
+ *	chg: kernel 2.4 adaption
+ *	
+ *	Revision 1.12  2001/03/01 12:52:15  mlindner
+ *	Fixed ring size
+ *
+ *	Revision 1.11  2001/02/19 13:28:02  mlindner
+ *	Changed PNMI parameter values
+ *
+ *	Revision 1.10  2001/01/22 14:16:04  mlindner
+ *	added ProcFs functionality
+ *	Dual Net functionality integrated
+ *	Rlmt networks added
+ *
+ *	Revision 1.1  2000/10/05 19:46:50  phargrov
+ *	Add directory src/vipk_devs_nonlbl/vipk_sk98lin/
+ *	This is the SysKonnect SK-98xx Gigabit Ethernet driver,
+ *	contributed by SysKonnect.
+ *
+ *	Revision 1.9  2000/02/21 10:39:55  cgoos
+ *	Added flag for jumbo support usage.
+ *
+ *	Revision 1.8  1999/11/22 13:50:44  cgoos
+ *	Changed license header to GPL.
+ *	Fixed two comments.
+ *
  *	Revision 1.7  1999/09/28 12:38:21  cgoos
  *	Added CheckQueue to SK_AC.
  *	
@@ -160,6 +186,11 @@
 #define SK_DRIVER_RESET(pAC, IoC)	0
 #define SK_DRIVER_SENDEVENT(pAC, IoC)	0
 #define SK_DRIVER_SELFTEST(pAC, IoC)	0
+/* For get mtu you must add an own function */
+#define SK_DRIVER_GET_MTU(pAc,IoC,i)	0
+#define SK_DRIVER_SET_MTU(pAc,IoC,i,v)	0
+#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v)	0
+
 
 /* TX and RX descriptors *****************************************************/
 
@@ -344,6 +375,16 @@
 
 #define IRQ_HWE_MASK	0x00000FFF /* enable all HW irqs */
 
+typedef struct s_DevNet DEV_NET;
+
+struct s_DevNet {
+	int             PortNr;
+	int             NetNr;
+	int             Mtu;
+	int             Up;
+	SK_AC   *pAC;
+};  
+
 typedef struct s_TxPort		TX_PORT;
 
 struct s_TxPort {
@@ -397,7 +438,8 @@
 	SK_RLMT		Rlmt;		/* for rlmt module */
 	spinlock_t	SlowPathLock;	/* Normal IRQ lock */
 	SK_PNMI_STRUCT_DATA PnmiStruct;	/* structure to get all Pnmi-Data */
-	int		RlmtMode;	/* link check mode to set */
+	int			RlmtMode;	/* link check mode to set */
+	int			RlmtNets;	/* Number of nets */
 	
 	SK_IOC		IoBase;		/* register set of adapter */
 	int		BoardLevel;	/* level of active hw init (0-2) */
@@ -405,7 +447,7 @@
 	SK_U32		AllocFlag;	/* flag allocation of resources */
 	struct pci_dev	PciDev;		/* for access to pci config space */
 	SK_U32		PciDevId;	/* pci device id */
-	struct net_device	*dev;		/* pointer to device struct */
+	struct net_device	*dev[2];		/* pointer to device struct */
 	char		Name[30];	/* driver name */
 	struct net_device	*Next;		/* link all devices (for clearing) */
 	int		RxBufSize;	/* length of receive buffers */
@@ -424,6 +466,7 @@
 					/*  (may be more than HW can)*/
 
 	int		ActivePort;	/* the active XMAC port */
+	int		MaxPorts;		/* number of activated ports */
 	int		TxDescrPerRing;	/* # of descriptors per tx ring */
 	int		RxDescrPerRing;	/* # of descriptors per rx ring */
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgehw.h linux/drivers/net/sk98lin/h/skgehw.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skgehw.h	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/h/skgehw.h	Wed Jul  4 11:50:39 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgehw.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.35 $
- * Date:	$Date: 2000/05/19 10:17:13 $
+ * Version:	$Revision: 1.36 $
+ * Date:	$Date: 2000/11/09 12:32:49 $
  * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product
  *		Family
  *
@@ -11,8 +11,7 @@
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2000 SysKonnect 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
@@ -27,6 +26,9 @@
  *
  * History:
  * $Log: skgehw.h,v $
+ * Revision 1.36  2000/11/09 12:32:49  rassmann
+ * Renamed variables.
+ *
  * Revision 1.35  2000/05/19 10:17:13  cgoos
  * Added inactivity check in PHY_READ (in DEBUG mode only).
  *
@@ -180,27 +182,27 @@
  */
 #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_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_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_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_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 	Capabilities Ptr */
+#define PCI_CAP_PTR		0x34	/*  8 bit 	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 */
+#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_1	0x40	/* 32 bit 	Our Register 1 */
 #define	PCI_OUR_REG_2	0x44	/* 32 bit 	Our Register 2 */
@@ -233,34 +235,34 @@
 /*	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 */
-				/* Bit 15..10:	reserved */
-#define	PCI_FBTEN	(1<<9)	/* Bit 9:	Fast Back-To-Back enable */
-#define	PCI_SERREN	(1<<8)	/* Bit 8:	SERR enable */
-#define	PCI_ADSTEP	(1<<7)	/* Bit 7:	Address Stepping */
-#define	PCI_PERREN	(1<<6)	/* Bit 6:	Parity Report Response enable */
+								/* Bit 15..10:	reserved */
+#define	PCI_FBTEN		(1<<9)	/* Bit 9:	Fast Back-To-Back enable */
+#define	PCI_SERREN		(1<<8)	/* Bit 8:	SERR enable */
+#define	PCI_ADSTEP		(1<<7)	/* Bit 7:	Address Stepping */
+#define	PCI_PERREN		(1<<6)	/* Bit 6:	Parity Report Response enable */
 #define	PCI_VGA_SNOOP	(1<<5)	/* Bit 5:	VGA palette snoop */
-#define	PCI_MWIEN	(1<<4)	/* Bit 4:	Memory write an inv cycl ena */
-#define	PCI_SCYCEN	(1<<3)	/* Bit 3:	Special Cycle enable */
-#define	PCI_BMEN	(1<<2)	/* Bit 2:	Bus Master enable */
-#define	PCI_MEMEN	(1<<1)	/* Bit 1:	Memory Space Access enable */
-#define	PCI_IOEN	(1<<0)	/* Bit 0:	IO Space Access enable */
+#define	PCI_MWIEN		(1<<4)	/* Bit 4:	Memory write an inv cycl ena */
+#define	PCI_SCYCEN		(1<<3)	/* Bit 3:	Special Cycle enable */
+#define	PCI_BMEN		(1<<2)	/* Bit 2:	Bus Master enable */
+#define	PCI_MEMEN		(1<<1)	/* Bit 1:	Memory Space Access enable */
+#define	PCI_IOEN		(1<<0)	/* Bit 0:	IO Space Access enable */
 
 /*	PCI_STATUS	16 bit	Status */
-#define	PCI_PERR	(1<<15)	/* Bit 15:	Parity Error */
-#define	PCI_SERR	(1<<14)	/* Bit 14:	Signaled SERR */
-#define	PCI_RMABORT	(1<<13)	/* Bit 13:	Received Master Abort */
-#define	PCI_RTABORT	(1<<12)	/* Bit 12:	Received Target Abort */
-				/* Bit 11:	reserved */
-#define	PCI_DEVSEL	(3<<9)	/* Bit 10..9:	DEVSEL Timing */
+#define	PCI_PERR		(1<<15)	/* Bit 15:	Parity Error */
+#define	PCI_SERR		(1<<14)	/* Bit 14:	Signaled SERR */
+#define	PCI_RMABORT		(1<<13)	/* Bit 13:	Received Master Abort */
+#define	PCI_RTABORT		(1<<12)	/* Bit 12:	Received Target Abort */
+								/* Bit 11:	reserved */
+#define	PCI_DEVSEL		(3<<9)	/* 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	(1<<8)	/* Bit 8:	DATA Parity error detected */
-#define	PCI_FB2BCAP	(1<<7)	/* Bit 7:	Fast Back-to-Back Capability */
-#define	PCI_UDF		(1<<6)	/* Bit 6:	User Defined Features */
+#define	PCI_FB2BCAP		(1<<7)	/* Bit 7:	Fast Back-to-Back Capability */
+#define	PCI_UDF			(1<<6)	/* Bit 6:	User Defined Features */
 #define PCI_66MHZCAP	(1<<5)	/* Bit 5:	66 MHz PCI bus clock capable */
-#define PCI_NEWCAP	(1<<4)	/* Bit 4:	New cap. list implemented */
-				/* Bit 3..0:	reserved */
+#define PCI_NEWCAP		(1<<4)	/* Bit 4:	New cap. list implemented */
+								/* Bit 3..0:	reserved */
 
 #define PCI_ERRBITS	(PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
 			PCI_DATAPERR)
@@ -275,59 +277,59 @@
 
 /*	PCI_HEADER_T	8 bit	Header Type */
 #define	PCI_HD_MF_DEV	(1<<7)	/* Bit 7:	0= single, 1= multi-func dev */
-#define	PCI_HD_TYPE	0x7f	/* Bit 6..0:	Header Layout 0= normal */
+#define	PCI_HD_TYPE		0x7f	/* Bit 6..0:	Header Layout 0= normal */
 
 /*	PCI_BIST	8 bit	Built-in selftest */
 /*	Built-in Self test not supported (optional) */
 
 /*	PCI_BASE_1ST	32 bit	1st Base address */
-#define	PCI_MEMSIZE	0x4000L		/* use 16 kB Memory Base */
+#define	PCI_MEMSIZE		0x4000L		/* use 16 kB Memory Base */
 #define	PCI_MEMBASE_MSK 0xffffc000L	/* Bit 31..14:	Memory Base Address */
 #define	PCI_MEMSIZE_MSK 0x00003ff0L	/* Bit 13.. 4:	Memory Size Req. */
-#define	PCI_PREFEN	(1L<<3)		/* Bit	3:	Prefetchable */
-#define	PCI_MEM_TYP	(3L<<2)		/* Bit	2.. 1:	Memory Type */
+#define	PCI_PREFEN		(1L<<3)		/* Bit	3:	Prefetchable */
+#define	PCI_MEM_TYP		(3L<<2)		/* Bit	2.. 1:	Memory Type */
 #define	PCI_MEM32BIT	(0L<<1)		/* Base addr anywhere in 32 Bit range */
-#define	PCI_MEM1M	(1L<<1)		/* Base addr below 1 MegaByte */
+#define	PCI_MEM1M		(1L<<1)		/* Base addr below 1 MegaByte */
 #define	PCI_MEM64BIT	(2L<<1)		/* Base addr anywhere in 64 Bit range */
 #define	PCI_MEMSPACE	(1L<<0)		/* 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 */
-					/* Bit	1:	reserved */
-#define	PCI_IOSPACE	(1L<<0)		/* Bit	0:	I/O Space Indicator */
+#define	PCI_IOBASE		0xffffff00L	/* Bit 31..8:	I/O Base address */
+#define	PCI_IOSIZE		0x000000fcL	/* Bit	7..2:	I/O Size Requirements */
+									/* Bit	1:	reserved */
+#define	PCI_IOSPACE		(1L<<0)		/* Bit	0:	I/O Space Indicator */
 
 /*	PCI_BASE_ROM	32 bit	Expansion ROM Base Address */
-#define	PCI_ROMBASE	(0xfffeL<<17)	/* Bit 31..17:	ROM BASE address (1st)*/
-#define	PCI_ROMBASZ	(0x1cL<<14)	/* Bit 16..14:	Treat as BASE or SIZE */
-#define	PCI_ROMSIZE	(0x38L<<11)	/* Bit 13..11:	ROM Size Requirements */
-					/* Bit 10.. 1:	reserved */
-#define	PCI_ROMEN	(0x1L<<0)	/* Bit 0:	Address Decode enable */
+#define	PCI_ROMBASE		(0xfffeL<<17)	/* Bit 31..17:	ROM BASE address (1st)*/
+#define	PCI_ROMBASZ		(0x1cL<<14)	/* Bit 16..14:	Treat as BASE or SIZE */
+#define	PCI_ROMSIZE		(0x38L<<11)	/* Bit 13..11:	ROM Size Requirements */
+									/* Bit 10.. 1:	reserved */
+#define	PCI_ROMEN		(0x1L<<0)	/* Bit 0:	Address Decode enable */
 
 /* Device Dependent Region */
 /*	PCI_OUR_REG_1		32 bit	Our Register 1 */
-					/* Bit 31..26:	reserved */
-#define PCI_VIO		(1L<<25)	/* Bit 25:	PCI IO Voltage, */
-					/*		0 = 3.3V / 1 = 5V */
-#define	PCI_EN_BOOT	(1L<<24)	/* Bit 24:	Enable BOOT via ROM */
-					/*		1 = Don't boot wth ROM*/
-					/*		0 = Boot with ROM */
-#define	PCI_EN_IO	(1L<<23)	/* Bit 23:	Mapping to IO space */
+									/* Bit 31..26:	reserved */
+#define PCI_VIO			(1L<<25)	/* Bit 25:	PCI IO Voltage, */
+									/*		0 = 3.3V / 1 = 5V */
+#define	PCI_EN_BOOT		(1L<<24)	/* Bit 24:	Enable BOOT via ROM */
+									/*		1 = Don't boot wth 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 Mem */
-					/*		0 = Disable addr. dec*/
+									/*		1 = Map Flash to Mem */
+									/*		0 = Disable addr. dec*/
 #define	PCI_PAGESIZE	(3L<<20)	/* Bit 21..20:	FLASH Page Size	*/
-#define	PCI_PAGE_16	(0L<<20)	/*		16 k pages	*/
+#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	*/
-#define	PCI_PAGEREG	(7L<<16)	/* Bit 18..16:	Page Register	*/
-#define PCI_NOTAR	(1L<<15)	/* Bit 15:	No turnaround cycle */
+									/* Bit 19:	reserved	*/
+#define	PCI_PAGEREG		(7L<<16)	/* Bit 18..16:	Page Register	*/
+#define PCI_NOTAR		(1L<<15)	/* Bit 15:	No turnaround cycle */
 #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_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_DIS_PCI_CLK	(1L<<8)		/* Bit	8:	Disable PCI clock driv*/
@@ -337,9 +339,9 @@
 
 /*	PCI_OUR_REG_2		32 bit	Our Register 2 */
 #define PCI_VPD_WR_THR	(0xffL<<24)	/* Bit 31..24:	VPD Write Threshold */
-#define	PCI_DEV_SEL	(0x7fL<<17)	/* Bit 23..17:	EEPROM Device Select */
+#define	PCI_DEV_SEL		(0x7fL<<17)	/* Bit 23..17:	EEPROM Device Select */
 #define	PCI_VPD_ROM_SZ	(7L<<14)	/* Bit 16..14:	VPD ROM Size	*/
-					/* Bit 13..12:	reserved	*/
+									/* Bit 13..12:	reserved	*/
 #define	PCI_PATCH_DIR	(0xfL<<8)	/* Bit 11.. 8:	Ext Patchs dir 3..0 */
 #define	PCI_PATCH_DIR_0	(1L<<8)
 #define	PCI_PATCH_DIR_1	(1L<<9)
@@ -352,27 +354,27 @@
 #define	PCI_EXT_PATCH_3	(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 */
-					/* Bit	1:	reserved */
+									/* Bit	1:	reserved */
 #define PCI_USEDATA64	(1L<<0)		/* Bit	0:	Use 64Bit Data bus ext*/
 
 
 /* Power Management Region */
 /*	PCI_PM_CAP_REG		16 bit	Power Management Capabilities */
-#define	PCI_PME_SUP	(0x1f<<11)	/* Bit 15..11:	PM Manag. Event Sup */
+#define	PCI_PME_SUP		(0x1f<<11)	/* Bit 15..11:	PM Manag. Event Sup */
 #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	8..6:	reserved */
-#define PCI_PM_DSI	(1<<5)		/* Bit	5:	Device Specific Init.*/
-#define PCI_PM_APS	(1<<4)		/* Bit	4:	Auxialiary Power Src */
+									/* Bit	8..6:	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	2..0:	PM PCI Spec. version */
+#define PCI_PM_VER		(7<<0)		/* Bit	2..0:	PM PCI Spec. version */
 
 /*	PCI_PM_CTL_STS		16 bit	Power Manag. Control/Status */
 #define	PCI_PME_STATUS	(1<<15)		/* Bit 15: 	PGA doesn't sup. PME# */
 #define PCI_PM_DAT_SCL	(3<<13)		/* Bit 14..13:	dat reg Scaling factor*/
 #define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit 12.. 9:	PM data selector field*/
-#define PCI_PME_EN	(1<<8)		/* Bit	8:	PGA doesn't sup. PME# */
-					/* Bit	7.. 2:	reserved */
+#define PCI_PME_EN		(1<<8)		/* Bit	8:	PGA doesn't sup. PME# */
+									/* Bit	7.. 2:	reserved */
 #define PCI_PM_STATE	(3<<0)		/* Bit	1.. 0:	Power Management State*/
 #define PCI_PM_STATE_D0	(0<<0)		/* D0:	Operational (default) */
 #define	PCI_PM_STATE_D1	(1<<0)		/* D1:	not supported */
@@ -388,22 +390,22 @@
  *	Control Register File:
  *	Bank 0
  */
-#define	B0_RAP		0x0000	/*  8 bit	Register Address Port */
+#define	B0_RAP			0x0000	/*  8 bit	Register Address Port */
 	/* 0x0001 - 0x0003:	reserved */
-#define	B0_CTST		0x0004	/* 16 bit	Control/Status register */
-#define	B0_LED		0x0006	/*  8 Bit	LED register */
+#define	B0_CTST			0x0004	/* 16 bit	Control/Status register */
+#define	B0_LED			0x0006	/*  8 Bit	LED register */
 	/* 0x0007:		reserved */
-#define	B0_ISRC		0x0008	/* 32 bit	Interrupt Source Register */
-#define	B0_IMSK		0x000c	/* 32 bit	Interrupt Mask Register */
-#define B0_HWE_ISRC	0x0010	/* 32 bit	HW Error Interrupt Src Reg */
-#define B0_HWE_IMSK	0x0014	/* 32 bit	HW Error Interrupt Mask Reg */
-#define B0_SP_ISRC	0x0018	/* 32 bit	Special Interrupt Source Reg */
+#define	B0_ISRC			0x0008	/* 32 bit	Interrupt Source Register */
+#define	B0_IMSK			0x000c	/* 32 bit	Interrupt Mask Register */
+#define B0_HWE_ISRC		0x0010	/* 32 bit	HW Error Interrupt Src Reg */
+#define B0_HWE_IMSK		0x0014	/* 32 bit	HW Error Interrupt Mask Reg */
+#define B0_SP_ISRC		0x0018	/* 32 bit	Special Interrupt Source Reg */
 	/* 0x001c:		reserved */
 
 /* B0 XMAC 1 registers */
-#define	B0_XM1_IMSK	0x0020	/* 16 bit r/w	XMAC 1 Interrupt Mask Register*/
+#define	B0_XM1_IMSK		0x0020	/* 16 bit r/w	XMAC 1 Interrupt Mask Register*/
 	/* 0x0022 - 0x0027	reserved */
-#define B0_XM1_ISRC	0x0028	/* 16 bit ro	XMAC 1 Interrupt Status Reg */
+#define B0_XM1_ISRC		0x0028	/* 16 bit ro	XMAC 1 Interrupt Status Reg */
 	/* 0x002a - 0x002f	reserved */
 #define B0_XM1_PHY_ADDR 0x0030	/* 16 bit r/w	XMAC 1 PHY Address Register */
 	/* 0x0032 - 0x0033	reserved */
@@ -411,9 +413,9 @@
 	/* 0x0036 - 0x003f	reserved */
 
 /* B0 XMAC 2 registers */
-#define	B0_XM2_IMSK	0x0040	/* 16 bit r/w	XMAC 2 Interrupt Mask Register*/
+#define	B0_XM2_IMSK		0x0040	/* 16 bit r/w	XMAC 2 Interrupt Mask Register*/
 	/* 0x0042 - 0x0047	reserved */
-#define B0_XM2_ISRC	0x0048	/* 16 bit ro	XMAC 2 Interrupt Status Reg */
+#define B0_XM2_ISRC		0x0048	/* 16 bit ro	XMAC 2 Interrupt Status Reg */
 	/* 0x004a - 0x004f	reserved */
 #define B0_XM2_PHY_ADDR 0x0050	/* 16 bit r/w	XMAC 2 PHY Address Register */
 	/* 0x0052 - 0x0053	reserved */
@@ -421,12 +423,12 @@
 				/* 0x0056 - 0x005f	reserved */
 
 /* BMU Control Status Registers */
-#define	B0_R1_CSR	0x0060	/* 32 bit	BMU Ctrl/Stat Rx Queue 1 */
-#define	B0_R2_CSR	0x0064	/* 32 bit	BMU Ctrl/Stat Rx Queue 2 */
-#define	B0_XS1_CSR	0x0068	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
-#define	B0_XA1_CSR	0x006c	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 1*/
-#define	B0_XS2_CSR	0x0070	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
-#define	B0_XA2_CSR	0x0074	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 2*/
+#define	B0_R1_CSR		0x0060	/* 32 bit	BMU Ctrl/Stat Rx Queue 1 */
+#define	B0_R2_CSR		0x0064	/* 32 bit	BMU Ctrl/Stat Rx Queue 2 */
+#define	B0_XS1_CSR		0x0068	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+#define	B0_XA1_CSR		0x006c	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 1*/
+#define	B0_XS2_CSR		0x0070	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+#define	B0_XA2_CSR		0x0074	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 2*/
 	/* x0078 - 0x007f	reserved */
 
 /*
@@ -440,34 +442,34 @@
  */
 /* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
 
-#define	B2_MAC_1	0x0100	/* NA reg	 MAC Address 1 */
+#define	B2_MAC_1		0x0100	/* NA reg	 MAC Address 1 */
 	/* 0x0106 - 0x0107	reserved */
-#define	B2_MAC_2	0x0108	/* NA reg	 MAC Address 2 */
+#define	B2_MAC_2		0x0108	/* NA reg	 MAC Address 2 */
 	/* 0x010e - 0x010f	reserved */
-#define	B2_MAC_3	0x0110	/* NA reg	 MAC Address 3 */
+#define	B2_MAC_3		0x0110	/* NA reg	 MAC Address 3 */
 	/* 0x0116 - 0x0117	reserved */
-#define B2_CONN_TYP	0x0118	/*  8 bit	Connector type */
-#define B2_PMD_TYP	0x0119	/*  8 bit	PMD type */
-#define B2_MAC_CFG	0x011a	/*  8 bit	MAC Configuration */
-#define B2_CHIP_REV	0x011b	/*  8 bit 	Queen Chip Revision Number */
+#define B2_CONN_TYP		0x0118	/*  8 bit	Connector type */
+#define B2_PMD_TYP		0x0119	/*  8 bit	PMD type */
+#define B2_MAC_CFG		0x011a	/*  8 bit	MAC Configuration */
+#define B2_CHIP_REV		0x011b	/*  8 bit 	Queen Chip Revision Number */
 	/* Eprom registers are currently of no use */
-#define B2_E_0		0x011c	/*  8 bit	EPROM Byte 0 */
-#define B2_E_1		0x011d	/*  8 bit	EPROM Byte 1 */
-#define B2_E_2		0x011e	/*  8 bit	EPROM Byte 2 */
-#define B2_E_3		0x011f	/*  8 bit	EPROM Byte 3 */
-#define B2_FAR		0x0120	/* 32 bit	Flash-Prom Addr Reg/Cnt */
-#define B2_FDP		0x0124	/*  8 bit	Flash-Prom Data Port */
+#define B2_E_0			0x011c	/*  8 bit	EPROM Byte 0 */
+#define B2_E_1			0x011d	/*  8 bit	EPROM Byte 1 */
+#define B2_E_2			0x011e	/*  8 bit	EPROM Byte 2 */
+#define B2_E_3			0x011f	/*  8 bit	EPROM Byte 3 */
+#define B2_FAR			0x0120	/* 32 bit	Flash-Prom Addr Reg/Cnt */
+#define B2_FDP			0x0124	/*  8 bit	Flash-Prom Data Port */
 	/* 0x0125 - 0x0127:	reserved */
-#define B2_LD_CRTL	0x0128	/*  8 bit	EPROM loader control register */
-#define B2_LD_TEST	0x0129	/*  8 bit	EPROM loader test register */
+#define B2_LD_CRTL		0x0128	/*  8 bit	EPROM loader control register */
+#define B2_LD_TEST		0x0129	/*  8 bit	EPROM loader test register */
 	/* 0x012a - 0x012f:	reserved */
-#define B2_TI_INI	0x0130	/* 32 bit	Timer init value */
-#define B2_TI_VAL	0x0134	/* 32 bit	Timer value */
-#define B2_TI_CRTL	0x0138	/*  8 bit	Timer control */
-#define B2_TI_TEST	0x0139	/*  8 Bit	Timer Test */
+#define B2_TI_INI		0x0130	/* 32 bit	Timer init value */
+#define B2_TI_VAL		0x0134	/* 32 bit	Timer value */
+#define B2_TI_CRTL		0x0138	/*  8 bit	Timer control */
+#define B2_TI_TEST		0x0139	/*  8 Bit	Timer Test */
 	/* 0x013a - 0x013f:	reserved */
-#define B2_IRQM_INI	0x0140	/* 32 bit	IRQ Moderation Timer Init Reg.*/
-#define B2_IRQM_VAL	0x0144	/* 32 bit	IRQ Moderation Timer Value */
+#define B2_IRQM_INI		0x0140	/* 32 bit	IRQ Moderation Timer Init Reg.*/
+#define B2_IRQM_VAL		0x0144	/* 32 bit	IRQ Moderation Timer Value */
 #define B2_IRQM_CTRL	0x0148	/*  8 bit	IRQ Moderation Timer Control */
 #define B2_IRQM_TEST	0x0149	/*  8 bit	IRQ Moderation Timer Test */
 #define B2_IRQM_MSK 	0x014c	/* 32 bit	IRQ Moderation Mask */
@@ -476,22 +478,22 @@
 #define	B2_TST_CTRL1	0x0158	/*  8 bit	Test Control Register 1 */
 #define B2_TST_CTRL2	0x0159	/*  8 bit	Test Control Register 2 */
 	/* 0x015a - 0x015b:	reserved */
-#define B2_GP_IO	0x015c	/* 32 bit	General Purpose IO Register */
-#define B2_I2C_CTRL	0x0160	/* 32 bit	I2C HW Control Register */
-#define B2_I2C_DATA	0x0164	/* 32 bit	I2C HW Data Register */
-#define B2_I2C_IRQ	0x0168	/* 32 bit	I2C HW IRQ Register */
-#define B2_I2C_SW	0x016c	/* 32 bit	I2C SW Port Register */
-#define B2_BSC_INI	0x0170	/* 32 bit	Blink Source Counter Init Val */
-#define B2_BSC_VAL	0x0174	/* 32 bit	Blink Source Counter Value */
-#define B2_BSC_CTRL	0x0178	/*  8 bit	Blink Source Counter Control */
-#define B2_BSC_STAT	0x0179	/*  8 bit	Blink Source Counter Status */
-#define B2_BSC_TST	0x017a	/* 16 bit	Blink Source Counter Test Reg */
+#define B2_GP_IO		0x015c	/* 32 bit	General Purpose IO Register */
+#define B2_I2C_CTRL		0x0160	/* 32 bit	I2C HW Control Register */
+#define B2_I2C_DATA		0x0164	/* 32 bit	I2C HW Data Register */
+#define B2_I2C_IRQ		0x0168	/* 32 bit	I2C HW IRQ Register */
+#define B2_I2C_SW		0x016c	/* 32 bit	I2C SW Port Register */
+#define B2_BSC_INI		0x0170	/* 32 bit	Blink Source Counter Init Val */
+#define B2_BSC_VAL		0x0174	/* 32 bit	Blink Source Counter Value */
+#define B2_BSC_CTRL		0x0178	/*  8 bit	Blink Source Counter Control */
+#define B2_BSC_STAT		0x0179	/*  8 bit	Blink Source Counter Status */
+#define B2_BSC_TST		0x017a	/* 16 bit	Blink Source Counter Test Reg */
 	/* 0x017c - 0x017f:	reserved */
 
 /*
  *	Bank 3
  */
-#define B3_RAM_ADDR	0x0180	/* 32 bit	RAM Address, to read or write */
+#define B3_RAM_ADDR		0x0180	/* 32 bit	RAM Address, to read or write */
 #define B3_RAM_DATA_LO	0x0184	/* 32 bit	RAM Data Word (low dWord) */
 #define B3_RAM_DATA_HI	0x0188	/* 32 bit	RAM Data Word (high dWord) */
 	/* 0x018c - 0x018f:	reserved */
@@ -499,7 +501,7 @@
 /*
  * The HW-Spec. call this registers Timeout Value 0..11. But this names are
  * not usable in SW. Please notice these are NOT real timeouts, these are
- * the number of qWords transferred continously.
+ * the number of qWords transfered continously.
  */
 #define B3_RI_WTO_R1	0x0190	/* 8 bit RAM Iface WR Timeout Queue R1	(TO0) */
 #define B3_RI_WTO_XA1	0x0191	/* 8 bit RAM Iface WR Timeout Queue XA1	(TO1) */
@@ -515,8 +517,8 @@
 #define B3_RI_RTO_XS2	0x019b	/* 8 bit RAM Iface RD Timeout Queue XS2	(TO11)*/
 #define B3_RI_TO_VAL	0x019c	/* 8 bit RAM Iface Current Timeout Count Val */
 	/* 0x019d - 0x019f	reserved */
-#define B3_RI_CTRL	0x01a0	/* 16 bit	RAM Iface Control Register */
-#define B3_RI_TEST	0x01a2	/*  8 bit	RAM Iface Test Register */
+#define B3_RI_CTRL		0x01a0	/* 16 bit	RAM Iface Control Register */
+#define B3_RI_TEST		0x01a2	/*  8 bit	RAM Iface Test Register */
 	/* 0x01a3 - 0x01af	reserved */
 /* MAC Arbiter Registers */
 /* Please notice these are the number of qWord tranfered continously and */
@@ -569,42 +571,42 @@
  */
 
 /* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */
-#define TXA_ITI_INI	0x0200	/* 32 bit	Tx Arb Interval Timer Init Val*/
-#define TXA_ITI_VAL	0x0204	/* 32 bit	Tx Arb Interval Timer Value */
-#define TXA_LIM_INI	0x0208	/* 32 bit	Tx Arb Limit Counter Init Val */
-#define TXA_LIM_VAL	0x020c	/* 32 bit	Tx Arb Limit Counter Value */
-#define TXA_CTRL	0x0210	/*  8 bit	Tx Arbiter Control Register */
-#define TXA_TEST	0x0211	/*  8 bit	Tx Arbiter Test Register */
-#define TXA_STAT	0x0212	/*  8 bit	Tx Arbiter Status Register */
+#define TXA_ITI_INI		0x0200	/* 32 bit	Tx Arb Interval Timer Init Val*/
+#define TXA_ITI_VAL		0x0204	/* 32 bit	Tx Arb Interval Timer Value */
+#define TXA_LIM_INI		0x0208	/* 32 bit	Tx Arb Limit Counter Init Val */
+#define TXA_LIM_VAL		0x020c	/* 32 bit	Tx Arb Limit Counter Value */
+#define TXA_CTRL		0x0210	/*  8 bit	Tx Arbiter Control Register */
+#define TXA_TEST		0x0211	/*  8 bit	Tx Arbiter Test Register */
+#define TXA_STAT		0x0212	/*  8 bit	Tx Arbiter Status Register */
 	/* 0x0213 - 0x027f:	reserved */
 
 /*
  *	Bank 6
  */
 /* External registers */
-#define B6_EXT_REG	0x0300
+#define B6_EXT_REG		0x0300
 
 /*
  *	Bank 7
  */
 /* This is a copy of the Configuration register file (lower half) */
-#define B7_CFG_SPC	0x0380
+#define B7_CFG_SPC		0x0380
 
 /*
  *	Bank 8 - 15
  */
 /* Receive and Transmit Queue Registers, use Q_ADDR() to access */
-#define	B8_Q_REGS	0x0400
+#define	B8_Q_REGS		0x0400
 
 /* Queue Register Offsets, use Q_ADDR() to access */
-#define Q_D	0x00	/* 8*32	bit	Current Descriptor */
+#define Q_D		0x00	/* 8*32	bit	Current Descriptor */
 #define Q_DA_L	0x20	/* 32 bit	Current Descriptor Address Low dWord */
 #define Q_DA_H	0x24	/* 32 bit	Current Descriptor Address High dWord */
 #define Q_AC_L	0x28	/* 32 bit	Current Address Counter Low dWord */
 #define Q_AC_H	0x2c	/* 32 bit	Current Address Counter High dWord */
 #define Q_BC	0x30	/* 32 bit	Current Byte Counter */
 #define Q_CSR	0x34	/* 32 bit	BMU Control/Status Register */
-#define Q_F	0x38	/* 32 bit	Flag Register */
+#define Q_F		0x38	/* 32 bit	Flag Register */
 #define Q_T1	0x3c	/* 32 bit	Test Register 1 */
 #define Q_T1_TR	0x3c	/*  8 bit	Test Register 1 Transfer SM */
 #define Q_T1_WR	0x3d	/*  8 bit	Test Register 1 Write Descriptor SM */
@@ -642,64 +644,64 @@
  *	Bank 24 - 25
  */
 /* Receive MAC FIFO, Receive LED, and Link Sync regs, use MR_ADDR() to address*/
-#define RX_MFF_EA	0x0c00	/* 32 bit	Receive MAC FIFO End Address */
-#define RX_MFF_WP	0x0c04	/* 32 bit 	Receive MAC FIFO Write Pointer*/
+#define RX_MFF_EA		0x0c00	/* 32 bit	Receive MAC FIFO End Address */
+#define RX_MFF_WP		0x0c04	/* 32 bit 	Receive MAC FIFO Write Pointer*/
 	/* 0x0c08 - 0x0c0b	reserved */
-#define RX_MFF_RP	0x0c0c	/* 32 bit	Receive MAC FIFO Read Pointer */
-#define RX_MFF_PC	0x0c10	/* 32 bit	Receive MAC FIFO Packet Cnt */
-#define RX_MFF_LEV	0x0c14	/* 32 bit	Receive MAC FIFO Level */
+#define RX_MFF_RP		0x0c0c	/* 32 bit	Receive MAC FIFO Read Pointer */
+#define RX_MFF_PC		0x0c10	/* 32 bit	Receive MAC FIFO Packet Cnt */
+#define RX_MFF_LEV		0x0c14	/* 32 bit	Receive MAC FIFO Level */
 #define RX_MFF_CTRL1	0x0c18	/* 16 bit	Receive MAC FIFO Control Reg 1*/
 #define RX_MFF_STAT_TO	0x0c1a	/*  8 bit	Receive MAC Status Timeout */
 #define RX_MFF_TIST_TO	0x0c1b	/*  8 bit	Receive MAC Timestamp Timeout */
 #define RX_MFF_CTRL2	0x0c1c	/*  8 bit	Receive MAC FIFO Control Reg 2*/
-#define RX_MFF_TST1	0x0c1d	/*  8 bit	Receive MAC FIFO Test Reg 1 */
-#define RX_MFF_TST2	0x0c1e	/*  8 bit	Receive MAC FIFO Test Reg 2 */
+#define RX_MFF_TST1		0x0c1d	/*  8 bit	Receive MAC FIFO Test Reg 1 */
+#define RX_MFF_TST2		0x0c1e	/*  8 bit	Receive MAC FIFO Test Reg 2 */
 	/* 0x0c1f		reserved */
-#define RX_LED_INI	0x0c20	/* 32 bit	Receive LED Cnt Init Value */
-#define RX_LED_VAL	0x0c24	/* 32 bit	Receive LED Cnt Current Value */
-#define RX_LED_CTRL	0x0c28	/*  8 bit	Receive LED Cnt Control Reg */
-#define RX_LED_TST	0x0c29	/*  8 bit	Receive LED Cnt Test Register */
+#define RX_LED_INI		0x0c20	/* 32 bit	Receive LED Cnt Init Value */
+#define RX_LED_VAL		0x0c24	/* 32 bit	Receive LED Cnt Current Value */
+#define RX_LED_CTRL		0x0c28	/*  8 bit	Receive LED Cnt Control Reg */
+#define RX_LED_TST		0x0c29	/*  8 bit	Receive LED Cnt Test Register */
 	/* 0x0c2a - 0x0c2f	reserved */
 #define LNK_SYNC_INI	0x0c30	/* 32 bit	Link Sync Cnt Init Value */
 #define LNK_SYNC_VAL	0x0c34	/* 32 bit	Link Sync Cnt Current Value */
 #define LNK_SYNC_CTRL	0x0c38	/*  8 bit	Link Sync Cnt Control Register*/
 #define LNK_SYNC_TST	0x0c39	/*  8 bit	Link Sync Cnt Test Register */
 	/* 0x0c3a - 0x0c3b	reserved */
-#define LNK_LED_REG	0x0c3c	/*  8 bit	Link LED Register */
+#define LNK_LED_REG		0x0c3c	/*  8 bit	Link LED Register */
 	/* 0x0c3d - 0x0c7f	reserved */
 
 /*
  *	Bank 26 - 27
  */
 /* Transmit MAC FIFO and Transmit LED Registers, use MR_ADDR() to address */
-#define TX_MFF_EA	0x0d00	/* 32 bit	Transmit MAC FIFO End Address */
-#define TX_MFF_WP	0x0d04	/* 32 bit 	Transmit MAC FIFO WR Pointer */
-#define TX_MFF_WSP	0x0d08	/* 32 bit	Transmit MAC FIFO WR Shadow Pt*/
-#define TX_MFF_RP	0x0d0c	/* 32 bit	Transmit MAC FIFO RD Pointer */
-#define TX_MFF_PC	0x0d10	/* 32 bit	Transmit MAC FIFO Packet Cnt */
-#define TX_MFF_LEV	0x0d14	/* 32 bit	Transmit MAC FIFO Level */
+#define TX_MFF_EA		0x0d00	/* 32 bit	Transmit MAC FIFO End Address */
+#define TX_MFF_WP		0x0d04	/* 32 bit 	Transmit MAC FIFO WR Pointer */
+#define TX_MFF_WSP		0x0d08	/* 32 bit	Transmit MAC FIFO WR Shadow Pt*/
+#define TX_MFF_RP		0x0d0c	/* 32 bit	Transmit MAC FIFO RD Pointer */
+#define TX_MFF_PC		0x0d10	/* 32 bit	Transmit MAC FIFO Packet Cnt */
+#define TX_MFF_LEV		0x0d14	/* 32 bit	Transmit MAC FIFO Level */
 #define TX_MFF_CTRL1	0x0d18	/* 16 bit	Transmit MAC FIFO Ctrl Reg 1 */
-#define TX_MFF_WAF	0x0d1a	/*  8 bit	Transmit MAC Wait after flush*/
+#define TX_MFF_WAF		0x0d1a	/*  8 bit	Transmit MAC Wait after flush*/
 	/* 0x0c1b		reserved */
 #define TX_MFF_CTRL2	0x0d1c	/*  8 bit	Transmit MAC FIFO Ctrl Reg 2 */
-#define TX_MFF_TST1	0x0d1d	/*  8 bit	Transmit MAC FIFO Test Reg 1 */
-#define TX_MFF_TST2	0x0d1e	/*  8 bit	Transmit MAC FIFO Test Reg 2 */
+#define TX_MFF_TST1		0x0d1d	/*  8 bit	Transmit MAC FIFO Test Reg 1 */
+#define TX_MFF_TST2		0x0d1e	/*  8 bit	Transmit MAC FIFO Test Reg 2 */
 	/* 0x0d1f		reserved */
-#define TX_LED_INI	0x0d20	/* 32 bit	Transmit LED Cnt Init Value */
-#define TX_LED_VAL	0x0d24	/* 32 bit	Transmit LED Cnt Current Val */
-#define TX_LED_CTRL	0x0d28	/*  8 bit	Transmit LED Cnt Control Reg */
-#define TX_LED_TST	0x0d29	/*  8 bit	Transmit LED Cnt Test Register*/
+#define TX_LED_INI		0x0d20	/* 32 bit	Transmit LED Cnt Init Value */
+#define TX_LED_VAL		0x0d24	/* 32 bit	Transmit LED Cnt Current Val */
+#define TX_LED_CTRL		0x0d28	/*  8 bit	Transmit LED Cnt Control Reg */
+#define TX_LED_TST		0x0d29	/*  8 bit	Transmit LED Cnt Test Register*/
 	/* 0x0d2a - 0x0d7f	reserved */
 
 /*
  *	Bank 28
  */
 /* Descriptor Poll Timer Registers */
-#define B28_DPT_INI	0x0e00	/* 32 bit	Descriptor Poll Timer Init Val*/
-#define B28_DPT_VAL	0x0e04	/* 32 bit	Descriptor Poll Timer Curr Val*/
+#define B28_DPT_INI		0x0e00	/* 32 bit	Descriptor Poll Timer Init Val*/
+#define B28_DPT_VAL		0x0e04	/* 32 bit	Descriptor Poll Timer Curr Val*/
 #define B28_DPT_CTRL	0x0e08	/*  8 bit	Descriptor Poll Timer Ctrl Reg*/
 	/* 0x0e09:		reserved */
-#define B28_DPT_TST	0x0e0a	/*  8 bit	Descriptor Poll Timer Test Reg*/
+#define B28_DPT_TST		0x0e0a	/*  8 bit	Descriptor Poll Timer Test Reg*/
 	/* 0x0e0b - 0x0e8f:	reserved */
 
 /*
@@ -739,7 +741,7 @@
  */
 /*	B0_RAP		8 bit	Register Address Port */
 				/* Bit 7:	reserved */
-#define	RAP_RAP		0x3f	/* Bit 6..0:	0 = block 0, .., 6f = block 6f*/
+#define	RAP_RAP			0x3f	/* Bit 6..0:	0 = block 0, .., 6f = block 6f*/
 
 /*	B0_CTST		16 bit	Control/Status register */
 				/* Bit 15..10:	reserved */
@@ -749,70 +751,70 @@
 #define CS_CL_SW_IRQ	(1<<6)	/* Bit	6:	Clear IRQ SW Request	*/
 #define CS_STOP_DONE	(1<<5)	/* Bit	5:	Stop Master is finished */
 #define	CS_STOP_MAST	(1<<4)	/* Bit	4:	Command Bit to stop the master*/
-#define	CS_MRST_CLR	(1<<3)	/* Bit	3:	Clear Master reset	*/
-#define	CS_MRST_SET	(1<<2)	/* Bit	2:	Set Master reset	*/
-#define	CS_RST_CLR	(1<<1)	/* Bit	1:	Clear Software reset	*/
-#define	CS_RST_SET	(1<<0)	/* Bit	0:	Set Software reset	*/
+#define	CS_MRST_CLR		(1<<3)	/* Bit	3:	Clear Master reset	*/
+#define	CS_MRST_SET		(1<<2)	/* Bit	2:	Set Master reset	*/
+#define	CS_RST_CLR		(1<<1)	/* Bit	1:	Clear Software reset	*/
+#define	CS_RST_SET		(1<<0)	/* Bit	0:	Set Software reset	*/
 
 /*	B0_LED		 8 Bit	LED register */
 				/* Bit 7..2:	reserved */
-#define LED_STAT_ON	(1<<1)	/* Bit 1:	Status LED on	*/
+#define LED_STAT_ON		(1<<1)	/* Bit 1:	Status LED on	*/
 #define LED_STAT_OFF	(1<<0)	/* Bit 0:	Status LED off	*/
 
 /*	B0_ISRC		32 bit	Interrupt Source Register */
 /*	B0_IMSK		32 bit	Interrupt Mask Register */
 /*	B0_SP_ISRC	32 bit	Special Interrupt Source Reg */
 /*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
-#define IS_ALL_MSK	0xbfffffffL	/* 		All Interrupt bits */
-#define IS_HW_ERR	(1UL<<31)	/* Bit 31:	Interrupt HW Error */
-					/* Bit 30:	reserved */
+#define IS_ALL_MSK		0xbfffffffL	/* 		All Interrupt bits */
+#define IS_HW_ERR		(1UL<<31)	/* Bit 31:	Interrupt HW Error */
+									/* Bit 30:	reserved */
 #define IS_PA_TO_RX1	(1L<<29)	/* Bit 29:	Packet Arb Timeout Rx1*/
 #define IS_PA_TO_RX2	(1L<<28)	/* Bit 28:	Packet Arb Timeout Rx2*/
 #define IS_PA_TO_TX1	(1L<<27)	/* Bit 27:	Packet Arb Timeout Tx1*/
 #define IS_PA_TO_TX2	(1L<<26)	/* Bit 26:	Packet Arb Timeout Tx2*/
 #define IS_I2C_READY	(1L<<25)	/* Bit 25:	IRQ on end of I2C tx */
-#define IS_IRQ_SW	(1L<<24)	/* Bit 24:	SW forced IRQ	*/
-#define IS_EXT_REG	(1L<<23)	/* Bit 23:	IRQ from external reg */
-#define	IS_TIMINT	(1L<<22)	/* Bit 22:	IRQ from Timer	*/
-#define IS_MAC1		(1L<<21)	/* Bit 21:	IRQ from MAC 1	*/
+#define IS_IRQ_SW		(1L<<24)	/* Bit 24:	SW forced IRQ	*/
+#define IS_EXT_REG		(1L<<23)	/* Bit 23:	IRQ from external reg */
+#define	IS_TIMINT		(1L<<22)	/* Bit 22:	IRQ from Timer	*/
+#define IS_MAC1			(1L<<21)	/* Bit 21:	IRQ from MAC 1	*/
 #define IS_LNK_SYNC_M1	(1L<<20)	/* Bit 20:	Link Sync Cnt wrap M1 */
-#define IS_MAC2		(1L<<19)	/* Bit 19:	IRQ from MAC 2	*/
+#define IS_MAC2			(1L<<19)	/* Bit 19:	IRQ from MAC 2	*/
 #define IS_LNK_SYNC_M2	(1L<<18)	/* Bit 18:	Link Sync Cnt wrap M2 */
 /* Receive Queue 1 */
-#define	IS_R1_B		(1L<<17)	/* Bit 17:	Q_R1 End of Buffer */
-#define	IS_R1_F		(1L<<16)	/* Bit 16:	Q_R1 End of Frame */
-#define	IS_R1_C		(1L<<15)	/* Bit 15:	Q_R1 Encoding Error */
+#define	IS_R1_B			(1L<<17)	/* Bit 17:	Q_R1 End of Buffer */
+#define	IS_R1_F			(1L<<16)	/* Bit 16:	Q_R1 End of Frame */
+#define	IS_R1_C			(1L<<15)	/* Bit 15:	Q_R1 Encoding Error */
 /* Receive Queue 2 */
-#define	IS_R2_B		(1L<<14)	/* Bit 14:	Q_R2 End of Buffer */
-#define	IS_R2_F		(1L<<13)	/* Bit 13:	Q_R2 End of Frame */
-#define	IS_R2_C		(1L<<12)	/* Bit 12:	Q_R2 Encoding Error */
+#define	IS_R2_B			(1L<<14)	/* Bit 14:	Q_R2 End of Buffer */
+#define	IS_R2_F			(1L<<13)	/* Bit 13:	Q_R2 End of Frame */
+#define	IS_R2_C			(1L<<12)	/* Bit 12:	Q_R2 Encoding Error */
 /* Synchronous Transmit Queue 1 */
-#define	IS_XS1_B	(1L<<11)	/* Bit 11:	Q_XS1 End of Buffer */
-#define	IS_XS1_F	(1L<<10)	/* Bit 10:	Q_XS1 End of Frame */
-#define	IS_XS1_C	(1L<<9)		/* Bit	9:	Q_XS1 Encoding Error */
+#define	IS_XS1_B		(1L<<11)	/* Bit 11:	Q_XS1 End of Buffer */
+#define	IS_XS1_F		(1L<<10)	/* Bit 10:	Q_XS1 End of Frame */
+#define	IS_XS1_C		(1L<<9)		/* Bit	9:	Q_XS1 Encoding Error */
 /* Asynchronous Transmit Queue 1 */
-#define	IS_XA1_B	(1L<<8)		/* Bit	8:	Q_XA1 End of Buffer */
-#define	IS_XA1_F	(1L<<7)		/* Bit	7:	Q_XA1 End of Frame */
-#define	IS_XA1_C	(1L<<6)		/* Bit	6:	Q_XA1 Encoding Error */
+#define	IS_XA1_B		(1L<<8)		/* Bit	8:	Q_XA1 End of Buffer */
+#define	IS_XA1_F		(1L<<7)		/* Bit	7:	Q_XA1 End of Frame */
+#define	IS_XA1_C		(1L<<6)		/* Bit	6:	Q_XA1 Encoding Error */
 /* Synchronous Transmit Queue 2 */
-#define	IS_XS2_B	(1L<<5)		/* Bit	5:	Q_XS2 End of Buffer */
-#define	IS_XS2_F	(1L<<4)		/* Bit	4:	Q_XS2 End of Frame */
-#define	IS_XS2_C	(1L<<3)		/* Bit	3:	Q_XS2 Encoding Error */
+#define	IS_XS2_B		(1L<<5)		/* Bit	5:	Q_XS2 End of Buffer */
+#define	IS_XS2_F		(1L<<4)		/* Bit	4:	Q_XS2 End of Frame */
+#define	IS_XS2_C		(1L<<3)		/* Bit	3:	Q_XS2 Encoding Error */
 /* Asynchronous Transmit Queue 2 */
-#define	IS_XA2_B	(1L<<2)		/* Bit	2:	Q_XA2 End of Buffer */
-#define	IS_XA2_F	(1L<<1)		/* Bit	1:	Q_XA2 End of Frame */
-#define	IS_XA2_C	(1L<<0)		/* Bit	0:	Q_XA2 Encoding Error */
+#define	IS_XA2_B		(1L<<2)		/* Bit	2:	Q_XA2 End of Buffer */
+#define	IS_XA2_F		(1L<<1)		/* Bit	1:	Q_XA2 End of Frame */
+#define	IS_XA2_C		(1L<<0)		/* Bit	0:	Q_XA2 Encoding Error */
 
 
 /*	B0_HWE_ISRC	32 bit	HW Error Interrupt Src Reg */
 /*	B0_HWE_IMSK	32 bit	HW Error Interrupt Mask Reg */
 /*	B2_IRQM_HWE_MSK 32 bit	IRQ Moderation HW Error Mask */
-#define IS_ERR_MSK	0x00000fffL	/* 		All Error bits */
-					/* Bit 31..12:	reserved */
+#define IS_ERR_MSK		0x00000fffL	/* 		All Error bits */
+									/* Bit 31..12:	reserved */
 #define	IS_IRQ_MST_ERR	(1L<<11)	/* Bit 11:	IRQ master error */
-					/*	PERR,RMABORT,RTABORT,DATAPERR */
-#define	IS_IRQ_STAT	(1L<<10)	/* Bit 10:	IRQ status execption */
-					/*	RMABORT, RTABORT, DATAPERR */
+									/*	PERR,RMABORT,RTABORT,DATAPERR */
+#define	IS_IRQ_STAT		(1L<<10)	/* Bit 10:	IRQ status execption */
+									/*	RMABORT, RTABORT, DATAPERR */
 #define IS_NO_STAT_M1	(1L<<9)		/* Bit	9:	No Rx Status from MAC1*/
 #define IS_NO_STAT_M2	(1L<<8)		/* Bit	8:	No Rx Status from MAC2*/
 #define IS_NO_TIST_M1	(1L<<7)		/* Bit	7:	No Timestamp from MAC1*/
@@ -829,53 +831,53 @@
 /*	Values of connector and PMD type comply to SysKonnect internal std */
 
 /*	B2_MAC_CFG	 8 bit	MAC Configuration */
-				/* Bit 7..2:	reserved */
+								/* Bit 7..2:	reserved */
 #define	CFG_DIS_M2_CLK	(1<<1)	/* Bit 1:	Disable Clock for 2nd MAC */
-#define CFG_SNG_MAC	(1<<0)	/* Bit 0:	MAC Config: 1=2 MACs / 0=1 MAC*/
+#define CFG_SNG_MAC		(1<<0)	/* Bit 0:	MAC Config: 1=2 MACs / 0=1 MAC*/
 
 /*	B2_CHIP_REV	 8 bit 	Queen Chip Revision Number */
 #define FIRST_CHIP_REV	0x0a	/* Initial Revision Value */
 
 /*	B2_FAR		32 bit	Flash-Prom Addr Reg/Cnt */
-#define	FAR_ADDR	0x1ffffL	/* Bit 16..0:	FPROM Address mask */
+#define	FAR_ADDR		0x1ffffL	/* Bit 16..0:	FPROM Address mask */
 
 /*	B2_LD_CRTL	 8 bit	EPROM loader control register */
 /*	Bits are currently reserved */
 
 /*	B2_LD_TEST	 8 bit	EPROM loader test register */
-				/* Bit 7..4:	reserved */
-#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 */
+								/* Bit 7..4:	reserved */
+#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 */
 
 /*
  *	Timer Section
  */
 /*	B2_TI_CRTL	 8 bit	Timer control */
 /*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
-				/* Bit 7..3:	reserved */
-#define TIM_START	(1<<2)	/* Bit 2:	Start Timer */
-#define TIM_STOP	(1<<1)	/* Bit 1:	Stop Timer */
-#define TIM_CLR_IRQ	(1<<0)	/* Bit 0:	Clear Timer IRQ, (!IRQM) */
+								/* Bit 7..3:	reserved */
+#define TIM_START		(1<<2)	/* Bit 2:	Start Timer */
+#define TIM_STOP		(1<<1)	/* Bit 1:	Stop Timer */
+#define TIM_CLR_IRQ		(1<<0)	/* Bit 0:	Clear Timer IRQ, (!IRQM) */
 
 /*	B2_TI_TEST	 8 Bit	Timer Test */
 /*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
 /*	B28_DPT_TST	 8 bit	Descriptor Poll Timer Test Reg */
-				/* Bit 7..3:	reserved */
-#define	TIM_T_ON	(1<<2)	/* Bit 2:	Test mode on */
-#define	TIM_T_OFF	(1<<1)	/* Bit 1:	Test mode off */
-#define	TIM_T_STEP	(1<<0)	/* Bit 0:	Test step */
+								/* Bit 7..3:	reserved */
+#define	TIM_T_ON		(1<<2)	/* Bit 2:	Test mode on */
+#define	TIM_T_OFF		(1<<1)	/* Bit 1:	Test mode off */
+#define	TIM_T_STEP		(1<<0)	/* Bit 0:	Test step */
 
 /*	B28_DPT_INI	32 bit	Descriptor Poll Timer Init Val */
 /*	B28_DPT_VAL	32 bit	Descriptor Poll Timer Curr Val */
-				/* Bit 31..24:	reserved */
-#define DPT_MSK	0x00ffffffL	/* Bit 23.. 0:	Desc Poll Timer Bits */
+								/* Bit 31..24:	reserved */
+#define DPT_MSK		0x00ffffffL	/* Bit 23.. 0:	Desc Poll Timer Bits */
 
 /*	B28_DPT_CTRL	 8 bit	Descriptor Poll Timer Ctrl Reg */
-				/* Bit 7..2:	reserved */
-#define DPT_START	(1<<1)	/* Bit 1:	Start Desciptor Poll Timer */
-#define DPT_STOP	(1<<0)	/* Bit 0:	Stop Desciptor Poll Timer */
+								/* Bit 7..2:	reserved */
+#define DPT_START		(1<<1)	/* Bit 1:	Start Desciptor Poll Timer */
+#define DPT_STOP		(1<<0)	/* Bit 0:	Stop Desciptor Poll Timer */
 
 
 /*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
@@ -889,7 +891,7 @@
 #define	TST_CFG_WRITE_OFF	(1<<0)	/* Bit 0: Disable Config Reg WR */
 
 /*	B2_TST_CTRL2	 8 bit	Test Control Register 2 */
-					/* Bit 7..4:	reserved */
+									/* 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	*/
@@ -898,7 +900,7 @@
 #define TST_FRC_APERR_2M64	(1<<0)	/* Bit 0:	AddrPERR on 2. phase */
 
 /*	B2_GP_IO	32 bit	General Purpose IO Register */
-					/* Bit 31..26:	reserved */
+								/* Bit 31..26:	reserved */
 #define	GP_DIR_9	(1L<<25)	/* Bit 25:	IO_9 direct, 0=I/1=O */
 #define	GP_DIR_8	(1L<<24)	/* Bit 24:	IO_8 direct, 0=I/1=O */
 #define	GP_DIR_7	(1L<<23)	/* Bit 23:	IO_7 direct, 0=I/1=O */
@@ -909,7 +911,7 @@
 #define	GP_DIR_2	(1L<<18)	/* Bit 18:	IO_2 direct, 0=I/1=O */
 #define	GP_DIR_1	(1L<<17)	/* Bit 17:	IO_1 direct, 0=I/1=O */
 #define	GP_DIR_0	(1L<<16)	/* Bit 16:	IO_0 direct, 0=I/1=O */
-					/* Bit 15..10:	reserved */
+								/* Bit 15..10:	reserved */
 #define	GP_IO_9		(1L<<9)		/* Bit	9:	IO_9 pin */
 #define	GP_IO_8		(1L<<8)		/* Bit	8:	IO_8 pin */
 #define	GP_IO_7		(1L<<7)		/* Bit	7:	IO_7 pin */
@@ -922,31 +924,31 @@
 #define	GP_IO_0		(1L<<0)		/* Bit	0:	IO_0 pin */
 
 /*	B2_I2C_CTRL	32 bit	I2C HW Control Register */
-#define	I2C_FLAG	(1UL<<31)	/* Bit 31:	Start read/write if WR*/
+#define	I2C_FLAG		(1UL<<31)	/* Bit 31:	Start read/write if WR*/
 #define I2C_ADDR	(0x7fffL<<16)	/* Bit 30..16:	Addr to be RD/WR */
-#define	I2C_DEV_SEL	(0x7fL<<9)	/* Bit 15.. 9:	I2C Device Select */
-					/* Bit	8.. 5:	reserved	*/
+#define	I2C_DEV_SEL		(0x7fL<<9)	/* Bit 15.. 9:	I2C Device Select */
+									/* Bit	8.. 5:	reserved	*/
 #define I2C_BURST_LEN	(1L<<4)		/* Bit	4:	Burst Len, 1/4 bytes */
 #define I2C_DEV_SIZE	(7L<<1)		/* Bit	3.. 1:	I2C Device Size	*/
 #define I2C_025K_DEV	(0L<<1)		/*		0: 256 Bytes or smal. */
-#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	(1L<<0)		/* Bit	0:	Interrupt I2C transfer*/
+#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		(1L<<0)		/* Bit	0:	Interrupt I2C transfer*/
 
 /*	B2_I2C_IRQ	32 bit	I2C HW IRQ Register */
-				/* Bit 31..1	reserved */
-#define I2C_CLR_IRQ	(1<<0)	/* Bit 0:	Clear I2C IRQ */
+								/* Bit 31..1	reserved */
+#define I2C_CLR_IRQ		(1<<0)	/* Bit 0:	Clear I2C IRQ */
 
 /*	B2_I2C_SW	32 bit	I2C HW SW Port Register */
-				/* Bit 7..3:	reserved */
+								/* Bit 7..3:	reserved */
 #define	I2C_DATA_DIR	(1<<2)	/* Bit 2:	direction of I2C_DATA */
-#define I2C_DATA	(1<<1)	/* Bit 1:	I2C Data Port	*/
-#define	I2C_CLK		(1<<0)	/* Bit 0:	I2C Clock Port	*/
+#define I2C_DATA		(1<<1)	/* Bit 1:	I2C Data Port	*/
+#define	I2C_CLK			(1<<0)	/* Bit 0:	I2C Clock Port	*/
 
 /*
  * I2C Address
@@ -955,12 +957,12 @@
 
 
 /*	B2_BSC_CTRL	 8 bit	Blink Source Counter Control */
-				/* Bit 7..2:	reserved */
+							/* Bit 7..2:	reserved */
 #define BSC_START	(1<<1)	/* Bit 1:	Start Blink Source Counter */
 #define BSC_STOP	(1<<0)	/* Bit 0:	Stop Blink Source Counter */
 
 /*	B2_BSC_STAT	 8 bit	Blink Source Counter Status */
-				/* Bit 7..1:	reserved */
+							/* Bit 7..1:	reserved */
 #define BSC_SRC		(1<<0)	/* Bit 0:	Blink Source, 0=Off / 1=On */
 
 /*	B2_BSC_TST	16 bit	Blink Source Counter Test Reg */
@@ -975,30 +977,30 @@
 
 /* RAM Interface Registers */
 /*	B3_RI_CTRL	16 bit	RAM Iface Control Register */
-				/* Bit 15..10:	reserved */
+								/* Bit 15..10:	reserved */
 #define RI_CLR_RD_PERR	(1<<9)	/* Bit	9:	Clear IRQ RAM Read Parity Err */
 #define RI_CLR_WR_PERR	(1<<8)	/* Bit	8:	Clear IRQ RAM Write Parity Err*/
-				/* Bit	7..2:	reserved */
-#define RI_RST_CLR	(1<<1)	/* Bit	1:	Clear RAM Interface Reset */
-#define RI_RST_SET	(1<<0)	/* Bit	0:	Set RAM Interface Reset */
+								/* Bit	7..2:	reserved */
+#define RI_RST_CLR		(1<<1)	/* Bit	1:	Clear RAM Interface Reset */
+#define RI_RST_SET		(1<<0)	/* Bit	0:	Set RAM Interface Reset */
 
 /*	B3_RI_TEST	 8 bit	RAM Iface Test Register */
-				/* Bit 15..4:	reserved */
-#define RI_T_EV		(1<<3)	/* Bit	3:	Timeout Event occurred */
-#define RI_T_ON		(1<<2)	/* Bit	2:	Timeout Timer Test On */
-#define RI_T_OFF	(1<<1)	/* Bit	1:	Timeout Timer Test Off */
-#define RI_T_STEP	(1<<0)	/* Bit	0:	Timeout Timer Step */
+								/* Bit 15..4:	reserved */
+#define RI_T_EV			(1<<3)	/* Bit	3:	Timeout Event occured */
+#define RI_T_ON			(1<<2)	/* Bit	2:	Timeout Timer Test On */
+#define RI_T_OFF		(1<<1)	/* Bit	1:	Timeout Timer Test Off */
+#define RI_T_STEP		(1<<0)	/* Bit	0:	Timeout Timer Step */
 
 /* MAC Arbiter Registers */
 /*	B3_MA_TO_CTRL	16 bit	MAC Arbiter Timeout Ctrl Reg */
-				/* Bit 15..4:	reserved */
-#define MA_FOE_ON	(1<<3)	/* Bit	3:	XMAC Fast Output Enable ON */
-#define MA_FOE_OFF	(1<<2)	/* Bit	2:	XMAC Fast Output Enable OFF */
-#define MA_RST_CLR	(1<<1)	/* Bit	1:	Clear MAC Arbiter Reset */
-#define MA_RST_SET	(1<<0)	/* Bit	0:	Set MAC Arbiter Reset */
+								/* Bit 15..4:	reserved */
+#define MA_FOE_ON		(1<<3)	/* Bit	3:	XMAC Fast Output Enable ON */
+#define MA_FOE_OFF		(1<<2)	/* Bit	2:	XMAC Fast Output Enable OFF */
+#define MA_RST_CLR		(1<<1)	/* Bit	1:	Clear MAC Arbiter Reset */
+#define MA_RST_SET		(1<<0)	/* Bit	0:	Set MAC Arbiter Reset */
 
 /*	B3_MA_RC_CTRL	16 bit	MAC Arbiter Recovery Ctrl Reg */
-				/* Bit 15..8:	reserved */
+								/* Bit 15..8:	reserved */
 #define MA_ENA_REC_TX2	(1<<7)	/* Bit	7:	Enable Recovery Timer TX2 */
 #define MA_DIS_REC_TX2	(1<<6)	/* Bit	6:	Disable Recovery Timer TX2 */
 #define MA_ENA_REC_TX1	(1<<5)	/* Bit	5:	Enable Recovery Timer TX1 */
@@ -1010,7 +1012,7 @@
 
 /* Packet Arbiter Registers */
 /*	B3_PA_CTRL	16 bit	Packet Arbiter Ctrl Register */
-				/* Bit 15..14:	reserved */
+								/* Bit 15..14:	reserved */
 #define PA_CLR_TO_TX2	(1<<13)	/* Bit 13:	Clear IRQ Packet Timeout TX2 */
 #define PA_CLR_TO_TX1	(1<<12)	/* Bit 12:	Clear IRQ Packet Timeout TX1 */
 #define PA_CLR_TO_RX2	(1<<11)	/* Bit 11:	Clear IRQ Packet Timeout RX2 */
@@ -1023,30 +1025,30 @@
 #define PA_DIS_TO_RX2	(1<<4)	/* Bit	4:	Disable Timeout Timer RX2 */
 #define PA_ENA_TO_RX1	(1<<3)	/* Bit	3:	Enable Timeout Timer RX1 */
 #define PA_DIS_TO_RX1	(1<<2)	/* Bit	2:	Disable Timeout Timer RX1 */
-#define PA_RST_CLR	(1<<1)	/* Bit	1:	Clear MAC Arbiter Reset */
-#define PA_RST_SET	(1<<0)	/* Bit	0:	Set MAC Arbiter Reset */
+#define PA_RST_CLR		(1<<1)	/* Bit	1:	Clear MAC Arbiter Reset */
+#define PA_RST_SET		(1<<0)	/* Bit	0:	Set MAC Arbiter Reset */
 
 #define PA_ENA_TO_ALL	(PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
-			 PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+						PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
 
 /* Rx/Tx Path related Arbiter Test Registers */
 /*	B3_MA_TO_TEST	16 bit	MAC Arbiter Timeout Test Reg */
 /*	B3_MA_RC_TEST	16 bit	MAC Arbiter Recovery Test Reg */
 /*	B3_PA_TEST	16 bit	Packet Arbiter Test Register */
 /*			Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
-#define TX2_T_EV	(1<<15)	/* Bit 15: 	TX2 Timeout/Recv Event occurred*/
+#define TX2_T_EV	(1<<15)	/* Bit 15: 	TX2 Timeout/Recv Event occured*/
 #define TX2_T_ON	(1<<14)	/* Bit 14:	TX2 Timeout/Recv Timer Test On*/
 #define TX2_T_OFF	(1<<13)	/* Bit 13:	TX2 Timeout/Recv Timer Tst Off*/
 #define TX2_T_STEP	(1<<12)	/* Bit 12:	TX2 Timeout/Recv Timer Step */
-#define TX1_T_EV	(1<<11)	/* Bit 11:	TX1 Timeout/Recv Event occurred*/
+#define TX1_T_EV	(1<<11)	/* Bit 11:	TX1 Timeout/Recv Event occured*/
 #define TX1_T_ON	(1<<10)	/* Bit 10:	TX1 Timeout/Recv Timer Test On*/
 #define TX1_T_OFF	(1<<9)	/* Bit	9:	TX1 Timeout/Recv Timer Tst Off*/
 #define TX1_T_STEP	(1<<8)	/* Bit	8:	TX1 Timeout/Recv Timer Step */
-#define RX2_T_EV	(1<<7)	/* Bit	7:	RX2 Timeout/Recv Event occurred*/
+#define RX2_T_EV	(1<<7)	/* Bit	7:	RX2 Timeout/Recv Event occured*/
 #define RX2_T_ON	(1<<6)	/* Bit	6:	RX2 Timeout/Recv Timer Test On*/
 #define RX2_T_OFF	(1<<5)	/* Bit	5:	RX2 Timeout/Recv Timer Tst Off*/
 #define RX2_T_STEP	(1<<4)	/* Bit	4:	RX2 Timeout/Recv Timer Step */
-#define RX1_T_EV	(1<<3)	/* Bit	3:	RX1 Timeout/Recv Event occurred*/
+#define RX1_T_EV	(1<<3)	/* Bit	3:	RX1 Timeout/Recv Event occured*/
 #define RX1_T_ON	(1<<2)	/* Bit	2:	RX1 Timeout/Recv Timer Test On*/
 #define RX1_T_OFF	(1<<1)	/* Bit	1:	RX1 Timeout/Recv Timer Tst Off*/
 #define RX1_T_STEP	(1<<0)	/* Bit	0:	RX1 Timeout/Recv Timer Step */
@@ -1057,7 +1059,7 @@
 /*	TXA_ITI_VAL	32 bit	Tx Arb Interval Timer Value */
 /*	TXA_LIM_INI	32 bit	Tx Arb Limit Counter Init Val */
 /*	TXA_LIM_VAL	32 bit	Tx Arb Limit Counter Value */
-					/* Bit 31..24:	reserved */
+								/* Bit 31..24:	reserved */
 #define	TXA_MAX_VAL	0x00ffffffL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
 
 /*	TXA_CTRL	 8 bit	Tx Arbiter Control Register */
@@ -1066,9 +1068,9 @@
 #define TXA_ENA_ALLOC	(1<<5)	/* Bit 5:	Enable alloc of free bandwidth*/
 #define TXA_DIS_ALLOC	(1<<4)	/* Bit 4:	Disabl alloc of free bandwidth*/
 #define TXA_START_RC	(1<<3)	/* Bit 3:	Start sync Rate Control */
-#define TXA_STOP_RC	(1<<2)	/* Bit 2:	Stop sync Rate Control */
-#define TXA_ENA_ARB	(1<<1)	/* Bit 1:	Enable Tx Arbiter */
-#define TXA_DIS_ARB	(1<<0)	/* Bit 0:	Disable Tx Arbiter */
+#define TXA_STOP_RC		(1<<2)	/* Bit 2:	Stop sync Rate Control */
+#define TXA_ENA_ARB		(1<<1)	/* Bit 1:	Enable Tx Arbiter */
+#define TXA_DIS_ARB		(1<<0)	/* Bit 0:	Disable Tx Arbiter */
 
 /*	TXA_TEST	 8 bit	Tx Arbiter Test Register */
 				/* Bit 7..6:	reserved */
@@ -1080,12 +1082,12 @@
 #define TXA_LIM_T_STEP	(1<<0)	/* Bit 0:	Tx Arb Limit Timer Step */
 
 /*	TXA_STAT	 8 bit	Tx Arbiter Status Register */
-				/* Bit 7..1:	reserved */
-#define	TXA_PRIO_XS	(1<<0)	/* Bit 0:	sync queue has prio to send */
+								/* Bit 7..1:	reserved */
+#define	TXA_PRIO_XS		(1<<0)	/* Bit 0:	sync queue has prio to send */
 
 /*	Q_BC	32 bit	Current Byte Counter */
 				/* Bit 31..16:	reserved */
-#define BC_MAX		0xffff	/* Bit 15.. 0:	Byte counter */
+#define BC_MAX			0xffff	/* Bit 15.. 0:	Byte counter */
 
 /* BMU Control Status Registers */
 /*	B0_R1_CSR	32 bit	BMU Ctrl/Stat Rx Queue 1 */
@@ -1095,47 +1097,47 @@
 /*	B0_XA2_CSR	32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
 /*	B0_XS2_CSR	32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
 /*	Q_CSR	32 bit	BMU Control/Status Register */
-					/* Bit 31..25:	reserved */
-#define CSR_SV_IDLE	(1L<<24)	/* Bit 24: 	BMU SM Idle */
-					/* Bit 23..22:	reserved */
+									/* Bit 31..25:	reserved */
+#define CSR_SV_IDLE		(1L<<24)	/* Bit 24: 	BMU SM Idle */
+									/* Bit 23..22:	reserved */
 #define	CSR_DESC_CLR	(1L<<21)	/* Bit 21:	Clear Reset for Descr */
 #define	CSR_DESC_SET	(1L<<20)	/* Bit 20:	Set Reset for Descr */
 #define	CSR_FIFO_CLR	(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_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 */
-#define CSR_ENA_POL	(1L<<7)		/* Bit	7:	Enable Descr Polling */
-#define CSR_DIS_POL	(1L<<6)		/* Bit	6:	Disable Descr Polling */
-#define CSR_STOP	(1L<<5)		/* Bit	5:	Stop Rx/Tx Queue */
-#define	CSR_START	(1L<<4)		/* Bit	4:	Start Rx/Tx Queue */
+#define CSR_ENA_POL		(1L<<7)		/* Bit	7:	Enable Descr Polling */
+#define CSR_DIS_POL		(1L<<6)		/* Bit	6:	Disable Descr Polling */
+#define CSR_STOP		(1L<<5)		/* Bit	5:	Stop Rx/Tx Queue */
+#define	CSR_START		(1L<<4)		/* Bit	4:	Start Rx/Tx Queue */
 #define	CSR_IRQ_CL_P	(1L<<3)		/* Bit	3: (Rx)	Clear Parity IRQ */
 #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)
+						CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST)
 #define CSR_CLR_RESET	(CSR_DESC_CLR|CSR_FIFO_CLR|CSR_HPI_RUN|CSR_SV_RUN|\
-			CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN)
+						CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN)
 
 
 /*	Q_F	32 bit	Flag Register */
 					/* Bit 28..31:	reserved */
-#define F_ALM_FULL	(1L<<27) (Rx)	/* Bit 27: (Rx)	FIFO almost full */
-#define F_EMPTY		(1L<<27) (Tx)	/* Bit 27: (Tx)	FIFO empty flag */
-#define F_FIFO_EOF	(1L<<26)	/* Bit 26: 	Fag bit in FIFO */
+#define F_ALM_FULL		(1L<<27) (Rx)	/* Bit 27: (Rx)	FIFO almost full */
+#define F_EMPTY			(1L<<27) (Tx)	/* Bit 27: (Tx)	FIFO empty flag */
+#define F_FIFO_EOF		(1L<<26)	/* Bit 26: 	Fag bit in FIFO */
 #define F_WM_REACHED	(1L<<25)	/* Bit 25: 	Watermark reached */
-					/* Bit 24:	reserved */
+									/* Bit 24:	reserved */
 #define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 23..16:	# of Qwords in FIFO */
-					/* Bit 15..11: 	reserved */
+									/* Bit 15..11: 	reserved */
 #define F_WATER_MARK	0x0007ffL	/* Bit 10.. 0:	Watermark */
 
 /*	Q_T1	32 bit	Test Register 1 */
@@ -1169,9 +1171,9 @@
 #define	T2_STEP01	(1<<0)	/* Bit 0:	Inc AC/Dec BC by 1 */
 
 /*	Q_T3	32 bit	Test Register 3	*/
-				/* Bit 31..7:	reserved */
+							/* Bit 31..7:	reserved */
 #define	T3_MUX		(7<<4)	/* Bit 6.. 4:	Mux Position */
-				/* Bit 3:	reserved */
+							/* Bit 3:	reserved */
 #define	T3_VRAM		(7<<0)	/* Bit 2.. 0:	Virtual RAM Buffer Address */
 
 /* RAM Buffer Register Offsets */
@@ -1190,7 +1192,7 @@
 #define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
 
 /*	RB_TST2		8 bit	RAM Buffer Test Register 2 */
-				/* Bit 4..7:	reserved */
+							/* Bit 4..7:	reserved */
 #define	RB_PC_DEC	(1<<3)	/* Bit 3:	Packet Counter Decrem */
 #define RB_PC_T_ON	(1<<2)	/* Bit 2:	Packet Counter Test On */
 #define RB_PC_T_OFF	(1<<1)	/* Bit 1:	Packet Counter Tst Off */
@@ -1201,19 +1203,19 @@
 #define RB_WP_T_ON	(1<<6)	/* Bit 6:	Write Pointer Test On */
 #define RB_WP_T_OFF	(1<<5)	/* Bit 5:	Write Pointer Test Off */
 #define RB_WP_INC	(1<<4)	/* Bit 4:	Write Pointer Increm */
-				/* Bit 3:	reserved */
+							/* Bit 3:	reserved */
 #define RB_RP_T_ON	(1<<2)	/* Bit 2:	Read Pointer Test On */
 #define RB_RP_T_OFF	(1<<1)	/* Bit 1:	Read Pointer Test Off */
 #define RB_RP_DEC	(1<<0)	/* Bit 0:	Read Pointer Decrement */
 
 /*	RB_CTRL		8 bit	RAM Buffer Control Register */
-				/* Bit	7..6:	reserved */
+								/* Bit	7..6:	reserved */
 #define RB_ENA_STFWD	(1<<5)	/* Bit	5:	Enable Store & Forward */
 #define RB_DIS_STFWD	(1<<4)	/* Bit	4:	Disab. Store & Forward */
 #define RB_ENA_OP_MD	(1<<3)	/* Bit	3:	Enable Operation Mode */
 #define RB_DIS_OP_MD	(1<<2)	/* Bit	2:	Disab. Operation Mode */
-#define RB_RST_CLR	(1<<1)	/* Bit	1:	Clr RAM Buf STM Reset */
-#define RB_RST_SET	(1<<0)	/* Bit	0:	Set RAM Buf STM Reset */
+#define RB_RST_CLR		(1<<1)	/* Bit	1:	Clr RAM Buf STM Reset */
+#define RB_RST_SET		(1<<0)	/* Bit	0:	Set RAM Buf STM Reset */
 
 
 /* Receive and Transmit MAC FIFO Registers, use MR_ADDR() to address */
@@ -1228,11 +1230,11 @@
 /*	TX_MFF_RP	32 bit	Transmit MAC FIFO Read Pointer */
 /*	TX_MFF_PC	32 bit	Transmit MAC FIFO Packet Cnt */
 /*	TX_MFF_LEV	32 bit	Transmit MAC FIFO Level */
-				/* Bit 31..6:	reserved */
+							/* Bit 31..6:	reserved */
 #define MFF_MSK		0x007fL	/* Bit	5..0:	MAC FIFO Address/Pointer Bits */
 
 /*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
-					/* Bit 15..14:	reserved */
+									/* Bit 15..14:	reserved */
 #define MFF_ENA_RDY_PAT	(1<<13)		/* Bit 13:	Enable Ready Patch */
 #define MFF_DIS_RDY_PAT	(1<<12)		/* Bit 12:	Disable Ready Patch */
 #define MFF_ENA_TIM_PAT	(1<<11)		/* Bit 11:	Enable Timing Patch */
@@ -1252,15 +1254,15 @@
 
 /*	TX_MFF_CTRL1	16 bit	Transmit MAC FIFO Control Reg 1 */
 #define MFF_CLR_PERR	(1<<15)		/* Bit 15:	Clear Parity Error IRQ*/
-					/* Bit 14:	reserved */
+									/* Bit 14:	reserved */
 #define MFF_ENA_PKT_REC	(1<<13)		/* Bit 13:	Enable Packet Recovery*/
 #define MFF_DIS_PKT_REC (1<<12)		/* Bit 12:	Disable Packet Recov. */
 /*	MFF_ENA_TIM_PAT	 (see RX_MFF_CTRL1)Bit 11:	Enable Timing Patch */
 /*	MFF_DIS_TIM_PAT	 (see RX_MFF_CTRL1)Bit 10:	Disable Timing Patch */
 /*	MFF_ENA_ALM_FUL	 (see RX_MFF_CTRL1)Bit	9:	Enable AlmostFull Sign*/
 /*	MFF_DIS_ALM_FUL	 (see RX_MFF_CTRL1)Bit	8:	Disab. AlmostFull Sign*/
-#define	MFF_ENA_W4E	(1<<7)		/* Bit	7:	Enable Wait for Empty */
-#define MFF_DIS_W4E	(1<<6)		/* Bit	6:	Disab. Wait for Empty */
+#define	MFF_ENA_W4E		(1<<7)		/* Bit	7:	Enable Wait for Empty */
+#define MFF_DIS_W4E		(1<<6)		/* Bit	6:	Disab. Wait for Empty */
 /*	MFF_ENA_FLUSH	 (see RX_MFF_CTRL1)Bit	5:	Enable Frame Flushing */
 /*	MFF_DIS_FLUSH	 (see RX_MFF_CTRL1)Bit	4:	Disab. Frame Flushing */
 #define MFF_ENA_LOOPB	(1<<3)		/* Bit	3:	Enable Loopback */
@@ -1272,61 +1274,61 @@
 
 /*	RX_MFF_TST2	 8 bit	Receive MAC FIFO Test Register 2 */
 /*	TX_MFF_TST2	 8 bit	Transmit MAC FIFO Test Register 2 */
-				/* Bit 7:	reserved */
+								/* Bit 7:	reserved */
 #define MFF_WSP_T_ON	(1<<6)	/* Bit 6: (Tx)	Write Shadow Pt TestOn */
 #define MFF_WSP_T_OFF	(1<<5)	/* Bit 5: (Tx)	Write Shadow Pt TstOff */
-#define MFF_WSP_INC	(1<<4)	/* Bit 4: (Tx)	Write Shadow Pt Increm */
-#define	MFF_PC_DEC	(1<<3)	/* Bit 3:	Packet Counter Decrem  */
-#define MFF_PC_T_ON	(1<<2)	/* Bit 2:	Packet Counter Test On */
+#define MFF_WSP_INC		(1<<4)	/* Bit 4: (Tx)	Write Shadow Pt Increm */
+#define	MFF_PC_DEC		(1<<3)	/* Bit 3:	Packet Counter Decrem  */
+#define MFF_PC_T_ON		(1<<2)	/* Bit 2:	Packet Counter Test On */
 #define MFF_PC_T_OFF	(1<<1)	/* Bit 1:	Packet Counter Tst Off */
-#define MFF_PC_INC	(1<<0)	/* Bit 0:	Packet Counter Increm  */
+#define MFF_PC_INC		(1<<0)	/* Bit 0:	Packet Counter Increm  */
 
 /*	RX_MFF_TST1	 8 bit	Receive MAC FIFO Test Register 1 */
 /*	TX_MFF_TST1	 8 bit	Transmit MAC FIFO Test Register 1 */
-				/* Bit 7:	reserved */
-#define MFF_WP_T_ON	(1<<6)	/* Bit 6:	Write Pointer Test On */
+					/* Bit 7:	reserved */
+#define MFF_WP_T_ON		(1<<6)	/* Bit 6:	Write Pointer Test On */
 #define MFF_WP_T_OFF	(1<<5)	/* Bit 5:	Write Pointer Test Off */
-#define MFF_WP_INC	(1<<4)	/* Bit 4:	Write Pointer Increm */
-				/* Bit 3:	reserved */
-#define MFF_RP_T_ON	(1<<2)	/* Bit 2:	Read Pointer Test On */
+#define MFF_WP_INC		(1<<4)	/* Bit 4:	Write Pointer Increm */
+								/* Bit 3:	reserved */
+#define MFF_RP_T_ON		(1<<2)	/* Bit 2:	Read Pointer Test On */
 #define MFF_RP_T_OFF	(1<<1)	/* Bit 1:	Read Pointer Test Off */
-#define MFF_RP_DEC	(1<<0)	/* Bit 0:	Read Pointer Decrement */
+#define MFF_RP_DEC		(1<<0)	/* Bit 0:	Read Pointer Decrement */
 
 /*	RX_MFF_CTRL2	 8 bit	Receive MAC FIFO Control Reg 2 */
 /*	TX_MFF_CTRL2	 8 bit	Transmit MAC FIFO Control Reg 2 */
-				/* Bit 7..4:	reserved */
+								/* Bit 7..4:	reserved */
 #define MFF_ENA_OP_MD	(1<<3)	/* Bit 3:	Enable Operation Mode */
 #define MFF_DIS_OP_MD	(1<<2)	/* Bit 2:	Disab. Operation Mode */
-#define MFF_RST_CLR	(1<<1)	/* Bit 1:	Clear MAC FIFO Reset */
-#define MFF_RST_SET	(1<<0)	/* Bit 0:	Set MAC FIFO Reset */
+#define MFF_RST_CLR		(1<<1)	/* Bit 1:	Clear MAC FIFO Reset */
+#define MFF_RST_SET		(1<<0)	/* Bit 0:	Set MAC FIFO Reset */
 
 
 /* Receive, Transmit, and Link LED Counter Registers */
-/*	RX_LED_CTRL	 8 bit	Receive LED Cnt Control Reg */
-/*	TX_LED_CTRL	 8 bit	Transmit LED Cnt Control Reg */
-/*	LNK_SYNC_CTRL	 8 bit	Link Sync Cnt Control Register */
-				/* Bit 7..3:	reserved */
+/*	RX_LED_CTRL		8 bit	Receive LED Cnt Control Reg */
+/*	TX_LED_CTRL		8 bit	Transmit LED Cnt Control Reg */
+/*	LNK_SYNC_CTRL	8 bit	Link Sync Cnt Control Register */
+							/* Bit 7..3:	reserved */
 #define LED_START	(1<<2)	/* Bit 2:	Start Timer */
 #define LED_STOP	(1<<1)	/* Bit 1:	Stop Timer */
 #define LED_STATE	(1<<0)	/* Bit 0:(Rx/Tx)LED State, 1=LED on */
 #define LED_CLR_IRQ	(1<<0)	/* Bit 0:(Lnk) 	Clear Link IRQ */
 
-/*	RX_LED_TST	 8 bit	Receive LED Cnt Test Register */
-/*	TX_LED_TST	 8 bit	Transmit LED Cnt Test Register */
-/*	LNK_SYNC_TST	 8 bit	Link Sync Cnt Test Register */
-				/* Bit 7..3:	reserved */
+/*	RX_LED_TST		8 bit	Receive LED Cnt Test Register */
+/*	TX_LED_TST		8 bit	Transmit LED Cnt Test Register */
+/*	LNK_SYNC_TST	8 bit	Link Sync Cnt Test Register */
+							/* Bit 7..3:	reserved */
 #define LED_T_ON	(1<<2)	/* Bit 2:	LED Counter Testmode On */
 #define LED_T_OFF	(1<<1)	/* Bit 1:	LED Counter Testmode Off */
 #define LED_T_STEP	(1<<0)	/* Bit 0:	LED Counter Step */
 
 /*	LNK_LED_REG	 8 bit	Link LED Register */
-				/* Bit 7..6:	reserved */
-#define LED_BLK_ON	(1<<5)	/* Bit 5:	Link LED Blinking On */
-#define LED_BLK_OFF	(1<<4)	/* Bit 4:	Link LED Blinking Off */
-#define LED_SYNC_ON	(1<<3)	/* Bit 3:	Use Sync Wire to switch LED */
+								/* Bit 7..6:	reserved */
+#define LED_BLK_ON		(1<<5)	/* Bit 5:	Link LED Blinking On */
+#define LED_BLK_OFF		(1<<4)	/* Bit 4:	Link LED Blinking Off */
+#define LED_SYNC_ON		(1<<3)	/* Bit 3:	Use Sync Wire to switch LED */
 #define LED_SYNC_OFF	(1<<2)	/* Bit 2:	Disable Sync Wire Input */
-#define LED_ON		(1<<1)	/* Bit 1:	switch LED on */
-#define LED_OFF		(1<<0)	/* Bit 0:	switch LED off */
+#define LED_ON			(1<<1)	/* Bit 1:	switch LED on */
+#define LED_OFF			(1<<0)	/* Bit 0:	switch LED off */
 
 
 /* Receive and Transmit Descriptors ******************************************/
@@ -1334,42 +1336,42 @@
 /* Transmit Descriptor struct */
 typedef	struct s_HwTxd {
 	SK_U32 volatile	TxCtrl;	/* Transmit Buffer Control Field */
-	SK_U32	TxNext ;	/* Physical Address Pointer to the next TxD */
-	SK_U32	TxAdrLo ;	/* Physical Tx Buffer Address lower dword */
-	SK_U32	TxAdrHi ;	/* Physical Tx Buffer Address upper dword */
-	SK_U32	TxStat ;	/* Transmit Frame Status Word */
+	SK_U32	TxNext;			/* Physical Address Pointer to the next TxD */
+	SK_U32	TxAdrLo;		/* Physical Tx Buffer Address lower dword */
+	SK_U32	TxAdrHi;		/* Physical Tx Buffer Address upper dword */
+	SK_U32	TxStat;			/* Transmit Frame Status Word */
 #ifndef	SK_USE_REV_DESC
-	SK_U16	TxTcpOffs ;	/* TCP Checksum Calculation Start Value */
-	SK_U16	TxRes1 ;	/* 16 bit reserved field */
-	SK_U16	TxTcpWp ;	/* TCP Checksum Write Position */
-	SK_U16	TxTcpSp ;	/* TCP Checksum Calculation Start Position */
+	SK_U16	TxTcpOffs;		/* TCP Checksum Calculation Start Value */
+	SK_U16	TxRes1;			/* 16 bit reserved field */
+	SK_U16	TxTcpWp;		/* TCP Checksum Write Position */
+	SK_U16	TxTcpSp;		/* TCP Checksum Calculation Start Position */
 #else	/* SK_USE_REV_DESC */
-	SK_U16	TxRes1 ;	/* 16 bit reserved field */
-	SK_U16	TxTcpOffs ;	/* TCP Checksum Calculation Start Value */
-	SK_U16	TxTcpSp ;	/* TCP Checksum Calculation Start Position */
-	SK_U16	TxTcpWp ;	/* TCP Checksum Write Position */
+	SK_U16	TxRes1;			/* 16 bit reserved field */
+	SK_U16	TxTcpOffs;		/* TCP Checksum Calculation Start Value */
+	SK_U16	TxTcpSp;		/* TCP Checksum Calculation Start Position */
+	SK_U16	TxTcpWp;		/* TCP Checksum Write Position */
 #endif	/* SK_USE_REV_DESC */
-	SK_U32  TxRes2;		/* 32 bit reserved field */
+	SK_U32  TxRes2;			/* 32 bit reserved field */
 } SK_HWTXD;
 
 /* Receive Descriptor struct */
 typedef	struct s_HwRxd {
 	SK_U32 volatile RxCtrl;	/* Receive Buffer Control Field */
-	SK_U32	RxNext ;	/* Physical Address Pointer to the next TxD */
-	SK_U32	RxAdrLo ;	/* Physical Receive Buffer Address lower dword*/
-	SK_U32	RxAdrHi ;	/* Physical Receive Buffer Address upper dword*/
-	SK_U32	RxStat ;	/* Receive Frame Status Word */
-	SK_U32	RxTiSt ;	/* Receive Timestamp provided by the XMAC */
+	SK_U32	RxNext;		/* Physical Address Pointer to the next TxD */
+	SK_U32	RxAdrLo;	/* Physical Receive Buffer Address lower dword*/
+	SK_U32	RxAdrHi;	/* Physical Receive Buffer Address upper dword*/
+	SK_U32	RxStat;		/* Receive Frame Status Word */
+	SK_U32	RxTiSt;		/* Receive Timestamp provided by the XMAC */
 #ifndef	SK_USE_REV_DESC	
-	SK_U16	RxTcpSum1 ;	/* TCP Checksum 1 */
-	SK_U16	RxTcpSum2 ;	/* TCP Checksum 2 */
-	SK_U16	RxTcpSp1 ;	/* TCP Checksum Calculation Start Position 1 */
-	SK_U16	RxTcpSp2 ;	/* TCP Checksum Calculation Start Position 2 */
+	SK_U16	RxTcpSum1;	/* TCP Checksum 1 */
+	SK_U16	RxTcpSum2;	/* TCP Checksum 2 */
+	SK_U16	RxTcpSp1;	/* TCP Checksum Calculation Start Position 1 */
+	SK_U16	RxTcpSp2;	/* TCP Checksum Calculation Start Position 2 */
 #else	/* SK_USE_REV_DESC */
-	SK_U16	RxTcpSum2 ;	/* TCP Checksum 2 */
-	SK_U16	RxTcpSum1 ;	/* TCP Checksum 1 */
-	SK_U16	RxTcpSp2 ;	/* TCP Checksum Calculation Start Position 2 */
-	SK_U16	RxTcpSp1 ;	/* TCP Checksum Calculation Start Position 1 */
+	SK_U16	RxTcpSum2;	/* TCP Checksum 2 */
+	SK_U16	RxTcpSum1;	/* TCP Checksum 1 */
+	SK_U16	RxTcpSp2;	/* TCP Checksum Calculation Start Position 2 */
+	SK_U16	RxTcpSp1;	/* TCP Checksum Calculation Start Position 1 */
 #endif	/* SK_USE_REV_DESC */
 } SK_HWRXD;
 
@@ -1387,23 +1389,23 @@
 /* Descriptor Bit Definition */
 /*	TxCtrl		Transmit Buffer Control Field */
 /*	RxCtrl		Receive Buffer Control Field */
-#define	BMU_OWN		(1UL<<31)	/* Bit 31:	OWN bit: 0=host/1=BMU */
-#define	BMU_STF		(1L<<30)	/* Bit 30:	Start of Frame ? */
-#define	BMU_EOF		(1L<<29)	/* Bit 29:	End of Frame ?	*/
-#define	BMU_IRQ_EOB	(1L<<28)	/* Bit 28:	Req "End of Buff" IRQ */
-#define	BMU_IRQ_EOF	(1L<<27)	/* Bit 27:	Req "End of Frame" IRQ*/
+#define	BMU_OWN			(1UL<<31)	/* Bit 31:	OWN bit: 0=host/1=BMU */
+#define	BMU_STF			(1L<<30)	/* Bit 30:	Start of Frame ? */
+#define	BMU_EOF			(1L<<29)	/* Bit 29:	End of Frame ?	*/
+#define	BMU_IRQ_EOB		(1L<<28)	/* Bit 28:	Req "End of Buff" IRQ */
+#define	BMU_IRQ_EOF		(1L<<27)	/* Bit 27:	Req "End of Frame" IRQ*/
 /* TxCtrl specific bits */
-#define BMU_STFWD	(1L<<26)	/* Bit 26: (Tx)	Store&Forward Frame */
-#define BMU_NO_FCS	(1L<<25)	/* Bit 25: (Tx) disable XMAC FCS gener*/
-#define BMU_SW		(1L<<24)	/* Bit 24: (Tx)	1 bit res. for SW use */
+#define BMU_STFWD		(1L<<26)	/* Bit 26: (Tx)	Store&Forward Frame */
+#define BMU_NO_FCS		(1L<<25)	/* Bit 25: (Tx) disable XMAC FCS gener*/
+#define BMU_SW			(1L<<24)	/* Bit 24: (Tx)	1 bit res. for SW use */
 /* RxCtrl specific bits */
-#define	BMU_DEV_0	(1L<<26)	/* Bit 26: (Rx)	transfer data to Dev0 */
+#define	BMU_DEV_0		(1L<<26)	/* Bit 26: (Rx)	transfer data to Dev0 */
 #define BMU_STAT_VAL	(1L<<25)	/* Bit 25: (Rx)	RxStat Valid */
 #define BMU_TIST_VAL	(1L<<24)	/* Bit 24: (Rx)	RxTiSt Valid */
-					/* Bit 23..16:	BMU Check Opcodes */
-#define	BMU_CHECK	0x00550000L	/* 		Default BMU check */
+									/* Bit 23..16:	BMU Check Opcodes */
+#define	BMU_CHECK		0x00550000L	/* 		Default BMU check */
 #define	BMU_TCP_CHECK	0x00560000L	/* 		Descr with TCP ext */
-#define	BMU_BBC		0x0000FFFFL	/* Bit 15..0:	Buffer Byte Counter */
+#define	BMU_BBC			0x0000FFFFL	/* Bit 15..0:	Buffer Byte Counter */
 
 /*	TxStat		Transmit Frame Status Word */
 /*	RxStat		Receive Frame Status Word */
@@ -1420,8 +1422,8 @@
  * FlashProm specification
  */
 #define	MAX_PAGES	0x20000L	/* Every byte has a single page */
-#define	MAX_FADDR	1		/* 1 byte per page */
-#define	SKFDDI_PSZ	8		/* address PROM size */
+#define	MAX_FADDR	1			/* 1 byte per page */
+#define	SKFDDI_PSZ	8			/* address PROM size */
 
 /* macros ********************************************************************/
 
@@ -1507,7 +1509,7 @@
  *		(p)Val	Value or pointer to the value which should be read or
  *			written.
  *
- * usage:	XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value) ;
+ * usage:	XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value);
  */
 
 #ifdef	SK_LITTLE_ENDIAN
@@ -1520,19 +1522,19 @@
 
 #define	XMA(Mac,Reg)	(((0x1000 << (Mac)) + 0x1000) | ((Reg) << 1))
 
-#define XM_IN16(IoC,Mac,Reg,pVal)	SK_IN16((IoC),XMA((Mac),(Reg)),(pVal))
-#define XM_OUT16(IoC,Mac,Reg,Val)	SK_OUT16((IoC),XMA((Mac),(Reg)),(Val))
+#define XM_IN16(IoC,Mac,Reg,pVal)	SK_IN16((IoC), XMA((Mac), (Reg)), (pVal))
+#define XM_OUT16(IoC,Mac,Reg,Val)	SK_OUT16((IoC), XMA((Mac), (Reg)), (Val))
 
-#define XM_IN32(IoC,Mac,Reg,pVal) {					\
-	SK_IN16((IoC),XMA((Mac),(Reg)),					\
+#define XM_IN32(IoC,Mac,Reg,pVal) {						\
+	SK_IN16((IoC), XMA((Mac), (Reg)),					\
 		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]);		\
-	SK_IN16((IoC),XMA((Mac),(Reg+2)),				\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)),					\
 		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]);		\
 }
 
-#define XM_OUT32(IoC,Mac,Reg,Val) {					\
-	SK_OUT16((IoC),XMA((Mac),(Reg)), (SK_U16)((Val) & 0x0000ffffL));\
-	SK_OUT16((IoC),XMA((Mac),(Reg+2)),(SK_U16)(((Val)>>16) & 0x0000ffffL));\
+#define XM_OUT32(IoC,Mac,Reg,Val) {											\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0x0000ffffL));		\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)),(SK_U16)(((Val)>>16) & 0x0000ffffL));	\
 }
 
 /*
@@ -1540,67 +1542,67 @@
  */
 
 #define XM_INADDR(IoC, Mac, Reg, pVal) {				\
-	SK_U16	Word;							\
-	SK_U8	*pByte;							\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
 	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
 	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
-	pByte[0] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
 	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
-	pByte[2] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
 	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
-	pByte[4] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
 }
 
 #define XM_OUTADDR(IoC, Mac, Reg, pVal) {				\
-	SK_U8	*pByte;							\
+	SK_U8	*pByte;										\
 	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
 	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
-		 (((SK_U16)(pByte[0]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[1]) << 8) & 0xff00)));		\
-	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)			\
-		 (((SK_U16)(pByte[2]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[3]) << 8) & 0xff00)));		\
-	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)			\
-		 (((SK_U16)(pByte[4]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[5]) << 8) & 0xff00)));		\
+		(((SK_U16)(pByte[0]) & 0x00ff) |				\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff) |				\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff) |				\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
 }
 
 #define XM_INHASH(IoC, Mac, Reg, pVal) {				\
-	SK_U16	Word;							\
-	SK_U8	*pByte;							\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
 	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
 	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
-	pByte[0] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
 	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
-	pByte[2] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
 	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
-	pByte[4] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
 	SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word);			\
-	pByte[6] = (SK_U8) (Word  & 0x00ff);				\
-	pByte[7] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	pByte[6] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);			\
 }
 
 #define XM_OUTHASH(IoC, Mac, Reg, pVal) {				\
-	SK_U8	*pByte;							\
+	SK_U8	*pByte;										\
 	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
 	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
-		 (((SK_U16)(pByte[0]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[1]) << 8) & 0xff00)));		\
-	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)			\
-		 (((SK_U16)(pByte[2]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[3]) << 8) & 0xff00)));		\
-	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)			\
-		 (((SK_U16)(pByte[4]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[5]) << 8) & 0xff00)));		\
-	SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16)			\
-		 (((SK_U16)(pByte[6]) & 0x00ff)|			\
-		 (((SK_U16)(pByte[7]) << 8) & 0xff00)));		\
+		(((SK_U16)(pByte[0]) & 0x00ff)|					\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff)|					\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff)|					\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16)		\
+		(((SK_U16)(pByte[6]) & 0x00ff)|					\
+		(((SK_U16)(pByte[7]) << 8) & 0xff00)));			\
 }
 
 /*
@@ -1637,56 +1639,56 @@
  *          comes back. This is checked in DEBUG mode.
  */
 #ifndef DEBUG
-#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {			\
-	SK_U16 Mmu;  							\
-									\
-	XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr);	\
-	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));			\
-	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
-		do {  							\
-			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
-		} while ((Mmu & XM_MMU_PHY_RDY) == 0);			\
-		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));		\
-	}  								\
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {						\
+	SK_U16 Mmu;  														\
+																		\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);							\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
+	}  																	\
 }
 #else
-#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {			\
-	SK_U16 Mmu;  							\
-	int __i = 0;							\
-									\
-	XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr);	\
-	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));			\
-	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
-		do {  							\
-			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
-			__i++;						\
-			if (__i > 10000) {				\
-				SK_DBG_PRINTF("*****************************\n"); \
-				SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n"); \
-				SK_DBG_PRINTF("*****************************\n"); \
-				break;					\
-			}						\
-		} while ((Mmu & XM_MMU_PHY_RDY) == 0);			\
-		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));		\
-	}  								\
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {						\
+	SK_U16 Mmu;  														\
+	int __i = 0;														\
+																		\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+			__i++;														\
+			if (__i > 100000) {											\
+				SK_DBG_PRINTF("*****************************\n");		\
+				SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n");		\
+				SK_DBG_PRINTF("*****************************\n");		\
+				break;													\
+			}															\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);							\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
+	}  																	\
 }
 #endif
 
-#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {			\
-	SK_U16 Mmu;							\
-									\
-	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
-		do {  							\
-			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
-		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);			\
-	}  								\
-	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr);	\
-	XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val));			\
-	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
-		do {  							\
-			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
-		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);			\
-	}  								\
+#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {						\
+	SK_U16 Mmu;															\
+																		\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);							\
+	}  																	\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);							\
+	}  																	\
 }
 
 /*
@@ -1731,7 +1733,7 @@
  *	Mode	Mode to set for this LED
  */
 #define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \
-SK_OUT8(IoC, MR_ADDR(Port,LNK_LED_REG), Mode); 
+	SK_OUT8(IoC, MR_ADDR(Port,LNK_LED_REG), Mode); 
 
  
 /* typedefs *******************************************************************/
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgehwt.h linux/drivers/net/sk98lin/h/skgehwt.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skgehwt.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skgehwt.h	Wed Jul  4 11:50:39 2001
@@ -1,23 +1,32 @@
 /******************************************************************************
  *
  * Name:	skhwt.h
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.5 $
- * Date:	$Date: 1999/11/22 13:54:24 $
+ * Project:	Genesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 1998/08/19 09:50:58 $
  * Purpose:	Defines for the hardware timer functions
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1989-1998 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	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; either version 2 of the License, or
- *	(at your option) any later version.
- *
+ *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
+ *	The copyright notice above does not evidence any
+ *	actual or intended publication of such source code.
+ *
+ *	This Module contains Proprietary Information of SysKonnect
+ *	and should be treated as Confidential.
+ *
+ *	The information in this file is provided for the exclusive use of
+ *	the licensees of SysKonnect.
+ *	Such users have the right to use, modify, and incorporate this code
+ *	into products for purposes authorized by the license agreement
+ *	provided they include this notice and the associated copyright notice
+ *	with any such product.
  *	The information in this file is provided "AS IS" without warranty.
  *
  ******************************************************************************/
@@ -27,9 +36,6 @@
  * History:
  *
  *	$Log: skgehwt.h,v $
- *	Revision 1.5  1999/11/22 13:54:24  cgoos
- *	Changed license header to GPL.
- *	
  *	Revision 1.4  1998/08/19 09:50:58  gklug
  *	fix: remove struct keyword from c-code (see CCC) add typedefs
  *	
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgeinit.h linux/drivers/net/sk98lin/h/skgeinit.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skgeinit.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skgeinit.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgeinit.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.46 $
- * Date:	$Date: 2000/08/10 11:28:00 $
+ * Version:	$Revision: 1.51 $
+ * Date:	$Date: 2001/02/09 12:26:38 $
  * Purpose:	Structures and prototypes for the GE Init Module
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,22 @@
  * History:
  *
  *	$Log: skgeinit.h,v $
+ *	Revision 1.51  2001/02/09 12:26:38  cgoos
+ *	Inserted #ifdef DIAG for half duplex workaround timer.
+ *	
+ *	Revision 1.50  2001/02/07 07:56:40  rassmann
+ *	Corrected copyright.
+ *	
+ *	Revision 1.49  2001/01/31 15:32:18  gklug
+ *	fix: problem with autosensing an SR8800 switch
+ *	add: counter for autoneg timeouts
+ *	
+ *	Revision 1.48  2000/11/09 11:30:10  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *	
+ *	Revision 1.47  2000/10/18 12:22:40  cgoos
+ *	Added workaround for half duplex hangup.
+ *	
  *	Revision 1.46  2000/08/10 11:28:00  rassmann
  *	Editorial changes.
  *	Preserving 32-bit alignment in structs for the adapter context.
@@ -440,6 +455,12 @@
  */
 #define	SK_MAX_LRESTART	3	/* Max. 3 times the link is restarted */
 
+/*
+ * define max. autonegotiation timeouts before link detection in sense mode is
+ * reset.
+ */
+#define	SK_MAX_ANEG_TO	10	/* Max. 10 times the sense mode is reset */
+
 /* structures *****************************************************************/
 
 /*
@@ -453,8 +474,13 @@
 	SK_U64	PPrevRx;		/* Previous RxOk Counter checking */
 	SK_U64	PPrevFcs;		/* Previous FCS Error Counter checking */
 	SK_U64	PRxLim;			/* Previous RxOk Counter checking */
+	SK_U64	LastOctets;		/* For half duplex hang check */
+#ifndef SK_DIAG
+	SK_TIMER	HalfDupChkTimer;
+#endif
 	int		PLinkResCt;		/* Link Restart Counter */
 	int		PAutoNegTimeOut;/* AutoNegotiation timeout current value */
+	int		PAutoNegTOCt;	/* AutoNeg Timeout Counter */
 	int		PRxQSize;		/* Port Rx Queue Size in kB */
 	int		PXSQSize;		/* Port Synchronous Transmit Queue Size in kB */
 	int		PXAQSize;		/* Port Asynchronous Transmit Queue Size in kB*/
@@ -467,13 +493,17 @@
 	int		PRxQOff;		/* Rx Queue Address Offset */
 	int		PXsQOff;		/* Synchronous Tx Queue Address Offset */
 	int		PXaQOff;		/* Asynchronous Tx Queue Address Offset */
+	int		PhyType;		/* PHY used on this port */
+	SK_U16	PhyAddr;		/* MDIO/MDC PHY address */
 	SK_U16	PRxCmd;			/* Port Receive Command Configuration Value */
 	SK_U16	PIsave;			/* Saved Interrupt status word */
 	SK_U16	PSsave;			/* Saved PHY status word */
+	SK_U16	Align01;
 	SK_BOOL	PHWLinkUp;		/* The hardware Link is up (wireing) */
 	SK_BOOL	PState;			/* Is port initialized ? */
 	SK_BOOL	PLinkBroken;	/* Is Link broken ? */
 	SK_BOOL	PCheckPar;		/* Do we check for parity errors ? */
+	SK_BOOL	HalfDupTimerActive;
 	SK_U8	PLinkCap;		/* Link Capabilities */
 	SK_U8	PLinkModeConf;	/* Link Mode configured */
 	SK_U8	PLinkMode;		/* Link Mode currently used */
@@ -486,8 +516,7 @@
 	SK_U8	PMSStatus;		/* Master/Slave Status */
 	SK_U8	PAutoNegFail;	/* Autonegotiation fail flag */
 	SK_U8	PLipaAutoNeg;	/* Autonegotiation possible with Link Partner */
-	SK_U16	PhyAddr;		/* MDIO/MDC PHY address */
-	int	PhyType;	/* PHY used on this port */
+	SK_U8	Align02;
 } SK_GEPORT;
 
 /*
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgepnm2.h linux/drivers/net/sk98lin/h/skgepnm2.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skgepnm2.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skgepnm2.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgepnm2.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.28 $
- * Date:	$Date: 2000/08/03 15:12:48 $
+ * Version:	$Revision: 1.30 $
+ * Date:	$Date: 2001/02/06 10:03:41 $
  * Purpose:	Defines for Private Network Management Interface
  *
  ****************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,14 @@
  * History:
  *
  *	$Log: skgepnm2.h,v $
+ *	Revision 1.30  2001/02/06 10:03:41  mkunz
+ *	- Pnmi V4 dual net support added. Interface functions and macros extended
+ *	- Vpd bug fixed
+ *	- OID_SKGE_MTU added
+ *	
+ *	Revision 1.29  2001/01/22 13:41:37  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
  *	Revision 1.28  2000/08/03 15:12:48  rwahl
  *	- Additional comment for MAC statistic data structure.
  *	
@@ -159,8 +166,6 @@
 /*
  * VPD releated defines
  */
-#define SK_PNMI_VPD_ARR_SIZE	40
-#define SK_PNMI_VPD_STR_SIZE	5
 
 #define SK_PNMI_VPD_RW		1
 #define SK_PNMI_VPD_RO		2
@@ -201,7 +206,8 @@
 	int		Access;
 	int		(* Func)(SK_AC *pAc, SK_IOC pIo, int action,
 				SK_U32 Id, char* pBuf, unsigned int* pLen,
-				SK_U32 Instance, unsigned int TableIndex);
+				SK_U32 Instance, unsigned int TableIndex,
+                                SK_U32 NetNumber);
 	SK_U16		Param;
 } SK_PNMI_TAB_ENTRY;
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgepnmi.h linux/drivers/net/sk98lin/h/skgepnmi.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skgepnmi.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skgepnmi.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgepnmi.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.44 $
- * Date:	$Date: 2000/09/07 07:35:27 $
+ * Version:	$Revision: 1.48 $
+ * Date:	$Date: 2001/02/23 14:34:24 $
  * Purpose:	Defines for Private Network Management Interface
  *
  ****************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,25 @@
  * History:
  *
  *	$Log: skgepnmi.h,v $
+ *	Revision 1.48  2001/02/23 14:34:24  mkunz
+ *	Changed macro PHYS2INST. Added pAC to Interface
+ *	
+ *	Revision 1.47  2001/02/07 08:28:23  mkunz
+ *	- Added Oids: 	OID_SKGE_DIAG_ACTION
+ *					OID_SKGE_DIAG_RESULT
+ *					OID_SKGE_MULTICAST_LIST
+ *					OID_SKGE_CURRENT_PACKET_FILTER
+ *					OID_SKGE_INTERMEDIATE_SUPPORT
+ *	- Changed value of OID_SKGE_MTU
+ *	
+ *	Revision 1.46  2001/02/06 10:01:41  mkunz
+ *	- Pnmi V4 dual net support added. Interface functions and macros extended
+ *	- Vpd bug fixed
+ *	- OID_SKGE_MTU added
+ *	
+ *	Revision 1.45  2001/01/22 13:41:37  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
  *	Revision 1.44  2000/09/07 07:35:27  rwahl
  *	- removed NDIS counter specific data type.
  *	- fixed spelling for OID_SKGE_RLMT_PORT_PREFERRED.
@@ -48,13 +66,13 @@
  *	Revision 1.40  2000/03/31 13:51:34  rwahl
  *	Added SK_UPTR cast to offset calculation for PNMI struct fields;
  *	missing cast caused compiler warnings by Win64 compiler.
- *	
+ *
  *	Revision 1.39  1999/12/06 10:09:47  rwahl
  *	Added new error log message.
  *	
  *	Revision 1.38  1999/11/22 13:57:55  cgoos
  *	Changed license header to GPL.
- *	
+ *
  *	Revision 1.37  1999/09/14 14:25:32  rwahl
  *	Set MDB version for 1000Base-T (sensors, Master/Slave) changes.
  *	
@@ -112,7 +130,7 @@
  *	
  *	Revision 1.22  1998/11/03 12:05:51  mhaveman
  *	Added pAC parameter to counter macors.
- *	
+ *
  *	Revision 1.21  1998/11/02 10:47:36  mhaveman
  *	Added syslog messages for internal errors.
  *	
@@ -187,7 +205,7 @@
 #include "h/ski2c.h"
 #include "h/skaddr.h"
 #include "h/skrlmt.h"
-
+#include "h/skvpd.h"
 
 /*
  * Management Database Version
@@ -198,22 +216,23 @@
 /*
  * Event definitions
  */
-#define SK_PNMI_EVT_SIRQ_OVERFLOW	1	/* Counter overflow */
-#define SK_PNMI_EVT_SEN_WAR_LOW		2	/* Lower war thres exceeded */
-#define SK_PNMI_EVT_SEN_WAR_UPP		3	/* Upper war thres exceeded */
-#define SK_PNMI_EVT_SEN_ERR_LOW		4	/* Lower err thres exceeded */
-#define SK_PNMI_EVT_SEN_ERR_UPP		5	/* Upper err thres exceeded */
-#define SK_PNMI_EVT_CHG_EST_TIMER	6	/* Timer event for RLMT Chg */
+#define SK_PNMI_EVT_SIRQ_OVERFLOW		1	/* Counter overflow */
+#define SK_PNMI_EVT_SEN_WAR_LOW			2	/* Lower war thres exceeded */
+#define SK_PNMI_EVT_SEN_WAR_UPP			3	/* Upper war thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_LOW			4	/* Lower err thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_UPP			5	/* Upper err thres exceeded */
+#define SK_PNMI_EVT_CHG_EST_TIMER		6	/* Timer event for RLMT Chg */
 #define SK_PNMI_EVT_UTILIZATION_TIMER	7	/* Timer event for Utiliza. */
-#define SK_PNMI_EVT_CLEAR_COUNTER	8	/* Clear statistic counters */
-#define SK_PNMI_EVT_XMAC_RESET		9	/* XMAC will be reset */
+#define SK_PNMI_EVT_CLEAR_COUNTER		8	/* Clear statistic counters */
+#define SK_PNMI_EVT_XMAC_RESET			9	/* XMAC will be reset */
 
-#define SK_PNMI_EVT_RLMT_PORT_UP	10	/* Port came logically up */
-#define SK_PNMI_EVT_RLMT_PORT_DOWN	11	/* Port went logically down */
-#define SK_PNMI_EVT_RLMT_PORT_SWITCH	12	/* Switched active port */
+#define SK_PNMI_EVT_RLMT_PORT_UP		10	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_PORT_DOWN		11	/* Port went logically down */
 #define SK_PNMI_EVT_RLMT_SEGMENTATION	13	/* Two SP root bridges found */
 #define SK_PNMI_EVT_RLMT_ACTIVE_DOWN	14	/* Port went logically down */
-#define SK_PNMI_EVT_RLMT_ACTIVE_UP	15	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_ACTIVE_UP		15	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_SET_NETS		16	/* 1. Parameter is number of nets
+												1 = single net; 2 = dual net */
 
 /*
  * Return values
@@ -225,6 +244,7 @@
 #define SK_PNMI_ERR_READ_ONLY		4
 #define SK_PNMI_ERR_UNKNOWN_OID		5
 #define SK_PNMI_ERR_UNKNOWN_INST	6
+#define SK_PNMI_ERR_UNKNOWN_NET 	7
 
 
 /*
@@ -355,7 +375,7 @@
 #define OID_SKGE_CHKSM_RX_ERR_CTS	0xFF020113
 #define OID_SKGE_CHKSM_TX_OK_CTS	0xFF020114
 #define OID_SKGE_CHKSM_TX_UNABLE_CTS	0xFF020115
-			
+
 #define OID_SKGE_STAT_TX		0xFF020120
 #define OID_SKGE_STAT_TX_OCTETS		0xFF020121
 #define OID_SKGE_STAT_TX_BROADCAST	0xFF020122
@@ -412,7 +432,10 @@
 #define OID_SKGE_STAT_RX_1023		0xFF020155
 #define OID_SKGE_STAT_RX_MAX		0xFF020156
 #define OID_SKGE_STAT_RX_LONGFRAMES	0xFF020157
-			
+
+#define OID_SKGE_DIAG_ACTION		0xFF01011D
+#define OID_SKGE_DIAG_RESULT		0xFF01011E
+#define OID_SKGE_MTU		0xFF01011F
 #define OID_SKGE_PHYS_CUR_ADDR		0xFF010120
 #define OID_SKGE_PHYS_FAC_ADDR		0xFF010121
 #define OID_SKGE_PMD			0xFF010122
@@ -427,7 +450,9 @@
 #define OID_SKGE_PHY_OPERATION_CAP	0xFF01012B
 #define OID_SKGE_PHY_OPERATION_MODE	0xFF01012C
 #define OID_SKGE_PHY_OPERATION_STATUS	0xFF01012D
-			
+#define OID_SKGE_MULTICAST_LIST		0xFF01012E
+#define OID_SKGE_CURRENT_PACKET_FILTER		0xFF01012F
+
 #define OID_SKGE_TRAP			0xFF010130
 #define OID_SKGE_TRAP_NUMBER		0xFF010131
 
@@ -435,11 +460,12 @@
 #define OID_SKGE_RLMT_PORT_NUMBER	0xFF010141
 #define OID_SKGE_RLMT_PORT_ACTIVE	0xFF010142
 #define OID_SKGE_RLMT_PORT_PREFERRED	0xFF010143
+#define OID_SKGE_INTERMEDIATE_SUPPORT		0xFF010160
 #define OID_SKGE_RLMT_CHANGE_CTS	0xFF020160
 #define OID_SKGE_RLMT_CHANGE_TIME	0xFF020161
 #define OID_SKGE_RLMT_CHANGE_ESTIM	0xFF020162
 #define OID_SKGE_RLMT_CHANGE_THRES	0xFF020163
-			
+
 #define OID_SKGE_RLMT_PORT_INDEX	0xFF020164
 #define OID_SKGE_RLMT_STATUS		0xFF020165
 #define OID_SKGE_RLMT_TX_HELLO_CTS	0xFF020166
@@ -447,7 +473,7 @@
 #define OID_SKGE_RLMT_TX_SP_REQ_CTS	0xFF020168
 #define OID_SKGE_RLMT_RX_SP_CTS		0xFF020169
 
-#define OID_SKGE_RLMT_MONITOR_NUMBER	0xFF010150			
+#define OID_SKGE_RLMT_MONITOR_NUMBER	0xFF010150
 #define OID_SKGE_RLMT_MONITOR_INDEX	0xFF010151
 #define OID_SKGE_RLMT_MONITOR_ADDR	0xFF010152
 #define OID_SKGE_RLMT_MONITOR_ERRS	0xFF010153
@@ -471,7 +497,7 @@
 #define OID_SKGE_ERR_RECOVERY_CTS	0xFF02017E
 #define OID_SKGE_SYSUPTIME		0xFF02017F
 
-#define OID_SKGE_ALL_DATA		0xFF020190			
+#define OID_SKGE_ALL_DATA		0xFF020190
 
 
 #define	OID_SKGE_TRAP_SEN_WAR_LOW	500
@@ -600,26 +626,27 @@
 #define SK_PNMI_SET_DRIVER_VER(pAC,v)	((pAC)->Pnmi.pDriverVersion = \
 	(char *)(v))
 
-#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v) \
+
+#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \
 	{ \
-		(pAC)->Pnmi.TxSwQueueLen = (SK_U64)(v); \
-		if ((pAC)->Pnmi.TxSwQueueLen > (pAC)->Pnmi.TxSwQueueMax) { \
-			(pAC)->Pnmi.TxSwQueueMax = (pAC)->Pnmi.TxSwQueueLen; \
+		(pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \
+		if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \
+			(pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \
 		} \
 	}
-#define SK_PNMI_CNT_TX_RETRY(pAC)	(((pAC)->Pnmi.TxRetryCts)++)
-#define SK_PNMI_CNT_RX_INTR(pAC)	(((pAC)->Pnmi.RxIntrCts)++)
-#define SK_PNMI_CNT_TX_INTR(pAC)	(((pAC)->Pnmi.TxIntrCts)++)
-#define SK_PNMI_CNT_NO_RX_BUF(pAC)	(((pAC)->Pnmi.RxNoBufCts)++)
-#define SK_PNMI_CNT_NO_TX_BUF(pAC)	(((pAC)->Pnmi.TxNoBufCts)++)
-#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v) \
-	((pAC)->Pnmi.TxUsedDescrNo=(SK_U64)(v));
-#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v) \
+#define SK_PNMI_CNT_TX_RETRY(pAC,p)	(((pAC)->Pnmi.Port[p].TxRetryCts)++)
+#define SK_PNMI_CNT_RX_INTR(pAC,p)	(((pAC)->Pnmi.Port[p].RxIntrCts)++)
+#define SK_PNMI_CNT_TX_INTR(pAC,p)	(((pAC)->Pnmi.Port[p].TxIntrCts)++)
+#define SK_PNMI_CNT_NO_RX_BUF(pAC,p)	(((pAC)->Pnmi.Port[p].RxNoBufCts)++)
+#define SK_PNMI_CNT_NO_TX_BUF(pAC,p)	(((pAC)->Pnmi.Port[p].TxNoBufCts)++)
+#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \
+	((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v));
+#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \
 	{ \
-		((pAC)->Pnmi.RxDeliveredCts)++; \
-		(pAC)->Pnmi.RxOctetsDeliveredCts += (SK_U64)(v); \
+		((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \
+		(pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \
 	}
-#define SK_PNMI_CNT_ERR_RECOVERY(pAC)	(((pAC)->Pnmi.ErrRecoveryCts)++);
+#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p)	(((pAC)->Pnmi.Port[p].ErrRecoveryCts)++);
 
 #define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \
 	{ \
@@ -643,14 +670,18 @@
 #define SK_PNMI_PORT_LOG2INST(l)	((unsigned int)(l) + 1)
 #define SK_PNMI_PORT_PHYS2LOG(p)	((unsigned int)(p) + 1)
 #define SK_PNMI_PORT_LOG2PHYS(pAC,l)	((unsigned int)(l) - 1)
-#define SK_PNMI_PORT_PHYS2INST(p)	((unsigned int)(p) + 2)
+#define SK_PNMI_PORT_PHYS2INST(pAC,p)	\
+	(pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2))
 #define SK_PNMI_PORT_INST2PHYS(pAC,i)	((unsigned int)(i) - 2)
 
 /*
  * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct
  */
-#define SK_PNMI_VPD_ENTRIES		20
-#define SK_PNMI_VPD_DATALEN		128
+#define SK_PNMI_VPD_KEY_SIZE	5
+#define SK_PNMI_VPD_BUFSIZE		(VPD_SIZE)
+#define SK_PNMI_VPD_ENTRIES		(VPD_SIZE / 4)
+#define SK_PNMI_VPD_DATALEN		128 /*  Number of data bytes */
+
 #define SK_PNMI_MULTICAST_LISTLEN	64
 #define SK_PNMI_SENSOR_ENTRIES		(SK_MAX_SENSORS)
 #define SK_PNMI_CHECKSUM_ENTRIES	3
@@ -663,7 +694,7 @@
 #define SK_PNMI_TRAP_QUEUE_LEN		512
 
 typedef struct s_PnmiVpd {
-	char			VpdKey[5];
+	char			VpdKey[SK_PNMI_VPD_KEY_SIZE];
 	char			VpdValue[SK_PNMI_VPD_DATALEN];
 	SK_U8			VpdAccess;
 	SK_U8			VpdAction;
@@ -795,7 +826,7 @@
 	SK_U32			MgmtDBVersion;
 	SK_PNMI_REQUEST_STATUS	ReturnStatus;
 	SK_U32			VpdFreeBytes;
-	char			VpdEntriesList[SK_PNMI_VPD_DATALEN];
+	char			VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE];
 	SK_U32			VpdEntriesNumber;
 	SK_PNMI_VPD		Vpd[SK_PNMI_VPD_ENTRIES];
 	SK_U32			PortNumber;
@@ -805,6 +836,7 @@
 	char			HwDescr[SK_PNMI_STRINGLEN1];
 	char			HwVersion[SK_PNMI_STRINGLEN2];
 	SK_U16			Chipset;
+	SK_U32			MtuSize;
 	SK_U32			Action;
 	SK_U32			TestResult;
 	SK_U8			BusType;
@@ -885,8 +917,24 @@
 	SK_U64			StatSyncOctetsCts;
 	SK_U64			StatRxLongFrameCts;
 	SK_BOOL			ActiveFlag;
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			RxHwErrorsCts;
+	SK_U64			TxHwErrorsCts;
+	SK_U64			InErrorsCts;
+	SK_U64			OutErrorsCts;
+	SK_U64			ErrRecoveryCts;
 } SK_PNMI_PORT;
 
+
 typedef struct s_PnmiData {
 	SK_PNMI_PORT		Port[SK_MAX_MACS];
 	SK_U64			VirtualCounterOffset[SK_PNMI_CNT_NO];
@@ -917,19 +965,8 @@
 	char			PciBusWidth;
 	char			PMD;
 	char			Connector;
-
-	SK_U64			TxSwQueueLen;
-	SK_U64			TxSwQueueMax;
-	SK_U64			TxRetryCts;
-	SK_U64			RxIntrCts;
-	SK_U64			TxIntrCts;
-	SK_U64			RxNoBufCts;
-	SK_U64			TxNoBufCts;
-	SK_U64			TxUsedDescrNo;
-	SK_U64			RxDeliveredCts;
-	SK_U64			RxOctetsDeliveredCts;
-	SK_U64			ErrRecoveryCts;
 	SK_U64			StartUpTime;
+	SK_BOOL			DualNetActiveFlag;
 } SK_PNMI;
 
 
@@ -938,17 +975,17 @@
  */
 extern int SkPnmiInit(SK_AC *pAc, SK_IOC IoC, int level);
 extern int SkPnmiGetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf,
-	unsigned int* pLen, SK_U32 Instance);
+	unsigned int* pLen, SK_U32 Instance, SK_U32 NetIndex);
 extern int SkPnmiPreSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id,
-	void* pBuf, unsigned int *pLen, SK_U32 Instance);
+	void* pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 extern int SkPnmiSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf,
-	unsigned int *pLen, SK_U32 Instance);
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 extern int SkPnmiGetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
-	unsigned int *pLen);
+	unsigned int *pLen, SK_U32 NetIndex);
 extern int SkPnmiPreSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
-	unsigned int *pLen);
+	unsigned int *pLen, SK_U32 NetIndex);
 extern int SkPnmiSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
-	unsigned int *pLen);
+	unsigned int *pLen, SK_U32 NetIndex);
 extern int SkPnmiEvent(SK_AC *pAc, SK_IOC IoC, SK_U32 Event,
 	SK_EVPARA Param);
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgesirq.h linux/drivers/net/sk98lin/h/skgesirq.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skgesirq.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skgesirq.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgesirq.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.20 $
- * Date:	$Date: 1999/12/06 10:00:44 $
+ * Version:	$Revision: 1.22 $
+ * Date:	$Date: 2000/11/09 11:30:10 $
  * Purpose:	SK specific Gigabit Ethernet special IRQ functions
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2000 SysKonnect 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
@@ -26,6 +25,12 @@
  *
  * History:
  *	$Log: skgesirq.h,v $
+ *	Revision 1.22  2000/11/09 11:30:10  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *	
+ *	Revision 1.21  2000/10/18 12:22:40  cgoos
+ *	Added workaround for half duplex hangup.
+ *	
  *	Revision 1.20  1999/12/06 10:00:44  cgoos
  *	Added SET event for role.
  *	
@@ -106,9 +111,12 @@
 #define SK_HWEV_SET_LMODE	6	/* Set Link Mode by PNMI */
 #define SK_HWEV_SET_FLOWMODE	7	/* Set Flow Control Mode by PNMI */
 #define SK_HWEV_SET_ROLE	8	/* Set Master/Slave (Role) by PNMI */
+#define SK_HWEV_HALFDUP_CHK	9	/* Set Master/Slave (Role) by PNMI */
 
 #define	SK_WA_ACT_TIME		(5000000L)	/* 5 sec */
 #define	SK_WA_INA_TIME		(100000L)	/* 100 msec */
+
+#define	SK_HALFDUP_CHK_TIME	(10000L)	/* 10 msec */
 
 /*
  * Define the error numbers and messages
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/ski2c.h linux/drivers/net/sk98lin/h/ski2c.h
--- v2.4.6/linux/drivers/net/sk98lin/h/ski2c.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/ski2c.h	Wed Jul  4 11:50:39 2001
@@ -2,8 +2,8 @@
  *
  * Name:	ski2c.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.29 $
- * Date:	$Date: 2000/08/03 14:28:17 $
+ * Version:	$Revision: 1.30 $
+ * Date:	$Date: 2001/04/05 11:38:09 $
  * Purpose:	Defines to access Voltage and Temperature Sensor
  *		(taken from Monalisa (taken from Concentrator))
  *
@@ -28,6 +28,10 @@
  * History:
  *
  *	$Log: ski2c.h,v $
+ *	Revision 1.30  2001/04/05 11:38:09  rassmann
+ *	Set SenState to idle in SkI2cWaitIrq().
+ *	Changed error message in SkI2cWaitIrq().
+ *	
  *	Revision 1.29  2000/08/03 14:28:17  rassmann
  *	- Added function to wait for I2C being ready before resetting the board.
  *	- Replaced one duplicate "out of range" message with correct one.
@@ -182,24 +186,26 @@
 #define	SKERR_I2C_E014MSG	"WARNING: fan sensor out of range"
 #define	SKERR_I2C_E015		(SKERR_I2C_E014+1)
 #define	SKERR_I2C_E015MSG	"ERROR: fan sensor out of range"
+#define	SKERR_I2C_E016		(SKERR_I2C_E015+1)
+#define	SKERR_I2C_E016MSG	"I2C: active transfer does not complete.\n"
 
 /*
  * Define Timeout values
  */
-#define	SK_I2C_TIM_LONG		2000000L	/* 2 second */
-#define	SK_I2C_TIM_SHORT	100000L		/* 100 milli second */
+#define	SK_I2C_TIM_LONG		2000000L	/* 2 seconds */
+#define	SK_I2C_TIM_SHORT	 100000L	/* 100 milliseconds */
 
 /*
  * Define trap and error log hold times
  */
 #ifndef	SK_SEN_ERR_TR_HOLD
-#define	SK_SEN_ERR_TR_HOLD	(4*SK_TICKS_PER_SEC)
+#define	SK_SEN_ERR_TR_HOLD		(4*SK_TICKS_PER_SEC)
 #endif
 #ifndef	SK_SEN_ERR_LOG_HOLD
-#define	SK_SEN_ERR_LOG_HOLD	(60*SK_TICKS_PER_SEC)
+#define	SK_SEN_ERR_LOG_HOLD		(60*SK_TICKS_PER_SEC)
 #endif
 #ifndef	SK_SEN_WARN_TR_HOLD
-#define	SK_SEN_WARN_TR_HOLD	(15*SK_TICKS_PER_SEC)
+#define	SK_SEN_WARN_TR_HOLD		(15*SK_TICKS_PER_SEC)
 #endif
 #ifndef	SK_SEN_WARN_LOG_HOLD
 #define	SK_SEN_WARN_LOG_HOLD	(15*60*SK_TICKS_PER_SEC)
@@ -268,3 +274,4 @@
 
 #endif
 #endif	/* n_SKI2C_H */
+
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skqueue.h linux/drivers/net/sk98lin/h/skqueue.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skqueue.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skqueue.h	Wed Jul  4 11:50:39 2001
@@ -1,23 +1,32 @@
 /******************************************************************************
  *
  * Name:	skqueue.h
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.13 $
- * Date:	$Date: 1999/11/22 13:59:05 $
+ * Project:	Genesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1998/09/08 08:48:01 $
  * Purpose:	Defines for the Event queue
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1989-1998 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	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; either version 2 of the License, or
- *	(at your option) any later version.
- *
+ *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
+ *	The copyright notice above does not evidence any
+ *	actual or intended publication of such source code.
+ *
+ *	This Module contains Proprietary Information of SysKonnect
+ *	and should be treated as Confidential.
+ *
+ *	The information in this file is provided for the exclusive use of
+ *	the licensees of SysKonnect.
+ *	Such users have the right to use, modify, and incorporate this code
+ *	into products for purposes authorized by the license agreement
+ *	provided they include this notice and the associated copyright notice
+ *	with any such product.
  *	The information in this file is provided "AS IS" without warranty.
  *
  ******************************************************************************/
@@ -27,9 +36,6 @@
  * History:
  *
  *	$Log: skqueue.h,v $
- *	Revision 1.13  1999/11/22 13:59:05  cgoos
- *	Changed license header to GPL.
- *	
  *	Revision 1.12  1998/09/08 08:48:01  gklug
  *	add: init level handling
  *	
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skrlmt.h linux/drivers/net/sk98lin/h/skrlmt.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skrlmt.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skrlmt.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skrlmt.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.27 $
- * Date:	$Date: 1999/11/22 13:59:56 $
+ * Version:	$Revision: 1.32 $
+ * Date:	$Date: 2001/02/14 14:06:31 $
  * Purpose:	Header file for Redundant Link ManagemenT.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,14 +26,26 @@
  * History:
  *
  *	$Log: skrlmt.h,v $
+ *	Revision 1.32  2001/02/14 14:06:31  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.31  2001/02/05 14:25:26  rassmann
+ *	Prepared RLMT for transparent operation.
+ *	
+ *	Revision 1.30  2001/01/22 13:41:39  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
+ *	Revision 1.29  2000/11/17 08:58:00  rassmann
+ *	Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event.
+ *	
+ *	Revision 1.28  2000/11/09 12:24:34  rassmann
+ *	Editorial changes.
+ *	
  *	Revision 1.27  1999/11/22 13:59:56  cgoos
  *	Changed license header to GPL.
  *	
  *	Revision 1.26  1999/10/04 14:01:19  rassmann
- *	Corrected reaction to reception of BPDU frames.
- *	Added parameter descriptions to "For Readme" section skrlmt.txt.
- *	Clarified usage of lookahead result *pForRlmt.
- *	Requested driver to present RLMT packets as soon as poosible.
+ *	Corrected reaction to reception of BPDU frames (#10441).
  *	
  *	Revision 1.25  1999/07/20 12:53:39  rassmann
  *	Fixed documentation errors for lookahead macros.
@@ -149,7 +160,7 @@
 #define __INC_SKRLMT_H
 
 #ifdef __cplusplus
-xxxx	/* not supported yet - force error */
+#error C++ is not yet supported.
 extern "C" {
 #endif	/* cplusplus */
 
@@ -169,128 +180,140 @@
 
 /* ----- PORT states ----- */
 
-#define SK_RLMT_PS_INIT		0	/* Port state: Init. */
+#define SK_RLMT_PS_INIT			0	/* Port state: Init. */
 #define SK_RLMT_PS_LINK_DOWN	1	/* Port state: Link down. */
-#define SK_RLMT_PS_DOWN		2	/* Port state: Port down. */
-#define SK_RLMT_PS_GOING_UP	3	/* Port state: Going up. */
-#define SK_RLMT_PS_UP		4	/* Port state: Up. */
+#define SK_RLMT_PS_DOWN			2	/* Port state: Port down. */
+#define SK_RLMT_PS_GOING_UP		3	/* Port state: Going up. */
+#define SK_RLMT_PS_UP			4	/* Port state: Up. */
 
 /* ----- RLMT states ----- */
 
-#define SK_RLMT_RS_INIT		0	/* RLMT state: Init. */
-#define SK_RLMT_RS_NET_DOWN	1	/* RLMT state: Net down. */
-#define SK_RLMT_RS_NET_UP	2	/* RLMT state: Net up. */
+#define SK_RLMT_RS_INIT			0	/* RLMT state: Init. */
+#define SK_RLMT_RS_NET_DOWN		1	/* RLMT state: Net down. */
+#define SK_RLMT_RS_NET_UP		2	/* RLMT state: Net up. */
 
 /* ----- PORT events ----- */
 
-#define SK_RLMT_LINK_UP		1001	/* Link came up. */
-#define SK_RLMT_LINK_DOWN	1002	/* Link went down. */
-#define SK_RLMT_PORT_ADDR	1003	/* Port address changed. */
+#define SK_RLMT_LINK_UP			1001	/* Link came up. */
+#define SK_RLMT_LINK_DOWN		1002	/* Link went down. */
+#define SK_RLMT_PORT_ADDR		1003	/* Port address changed. */
 
 /* ----- RLMT events ----- */
 
-#define SK_RLMT_START		2001	/* Start RLMT. */
-#define SK_RLMT_STOP		2002	/* Stop RLMT. */
+#define SK_RLMT_START			2001	/* Start RLMT. */
+#define SK_RLMT_STOP			2002	/* Stop RLMT. */
 #define SK_RLMT_PACKET_RECEIVED	2003	/* Packet was received for RLMT. */
-#define SK_RLMT_STATS_CLEAR	2004	/* Clear statistics. */
+#define SK_RLMT_STATS_CLEAR		2004	/* Clear statistics. */
 #define SK_RLMT_STATS_UPDATE	2005	/* Update statistics. */
 #define SK_RLMT_PREFPORT_CHANGE	2006	/* Change preferred port. */
-#define SK_RLMT_MODE_CHANGE	2007	/* New RlmtMode. */
+#define SK_RLMT_MODE_CHANGE		2007	/* New RlmtMode. */
+#define SK_RLMT_SET_NETS		2008	/* Number of Nets (1 or 2). */
 
 /* ----- RLMT mode bits ----- */
 
-#define SK_RLMT_CHECK_LINK	1	/* Check Link. */
-#define SK_RLMT_CHECK_LOC_LINK	2	/* Check other link on same adapter. */
-#define SK_RLMT_CHECK_SEG	4	/* Check segmentation. */
+/*
+ * CAUTION:	These defines are private to RLMT.
+ *			Please use the RLMT mode defines below.
+ */
+
+#define SK_RLMT_CHECK_LINK		  1		/* Check Link. */
+#define SK_RLMT_CHECK_LOC_LINK	  2		/* Check other link on same adapter. */
+#define SK_RLMT_CHECK_SEG		  4		/* Check segmentation. */
 
 #ifndef RLMT_CHECK_REMOTE
 #define SK_RLMT_CHECK_OTHERS	SK_RLMT_CHECK_LOC_LINK
 #else	/* RLMT_CHECK_REMOTE */
-#define SK_RLMT_CHECK_REM_LINK	8	/* Check link(s) on other adapter(s). */
+#define SK_RLMT_CHECK_REM_LINK	  8		/* Check link(s) on other adapter(s). */
 #define SK_RLMT_MAX_REMOTE_PORTS_CHECKED	3
-#define SK_RLMT_CHECK_OTHERS	(SK_RLMT_CHECK_LOC_LINK | \
-				 SK_RLMT_CHECK_REM_LINK)
+#define SK_RLMT_CHECK_OTHERS	\
+		(SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
 #endif	/* RLMT_CHECK_REMOTE */
 
+#ifndef SK_RLMT_ENABLE_TRANSPARENT
+#define SK_RLMT_TRANSPARENT		  0		/* RLMT transparent - inactive. */
+#else	/* SK_RLMT_ENABLE_TRANSPARENT */
+#define SK_RLMT_TRANSPARENT		128		/* RLMT transparent. */
+#endif	/* SK_RLMT_ENABLE_TRANSPARENT */
+
 /* ----- RLMT modes ----- */
 
 /* Check Link State. */
 #define SK_RLMT_MODE_CLS	(SK_RLMT_CHECK_LINK)
 
 /* Check Local Ports: check other links on the same adapter. */
-#define SK_RLMT_MODE_CLP	(SK_RLMT_CHECK_LINK | \
-				 SK_RLMT_CHECK_LOC_LINK)
+#define SK_RLMT_MODE_CLP	(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK)
 
 /* Check Local Ports and Segmentation Status. */
-#define SK_RLMT_MODE_CLPSS	(SK_RLMT_CHECK_LINK | \
-				 SK_RLMT_CHECK_LOC_LINK | \
-				 SK_RLMT_CHECK_SEG)
+#define SK_RLMT_MODE_CLPSS	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG)
 
 #ifdef RLMT_CHECK_REMOTE
 /* Check Local and Remote Ports: check links (local or remote). */
 	Name of define TBD!
-#define SK_RLMT_MODE_CRP	(SK_RLMT_CHECK_LINK | \
-				 SK_RLMT_CHECK_LOC_LINK | \
-				 SK_RLMT_CHECK_REM_LINK)
+#define SK_RLMT_MODE_CRP	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
 
 /* Check Local and Remote Ports and Segmentation Status. */
 	Name of define TBD!
-#define SK_RLMT_MODE_CRPSS	(SK_RLMT_CHECK_LINK | \
-				 SK_RLMT_CHECK_LOC_LINK | \
-				 SK_RLMT_CHECK_REM_LINK | \
-				 SK_RLMT_CHECK_SEG)
+#define SK_RLMT_MODE_CRPSS	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \
+		SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG)
 #endif	/* RLMT_CHECK_REMOTE */
 
 /* ----- RLMT lookahead result bits ----- */
 
-#define SK_RLMT_RX_RLMT		1	/* Give packet to RLMT. */
-#define SK_RLMT_RX_PROTOCOL	2	/* Give packet to protocol. */
+#define SK_RLMT_RX_RLMT			1	/* Give packet to RLMT. */
+#define SK_RLMT_RX_PROTOCOL		2	/* Give packet to protocol. */
 
 /* Macros */
 
 #if 0
 SK_AC		*pAC		/* adapter context */
-SK_U32		PortIdx		/* receiving port */
-unsigned	PacketLength	/* received packet's length */
-SK_BOOL		IsBc		/* Flag: broadcast received */
-unsigned	*pOffset	/* Result: offset of bytes to present
-				   to SK_RLMT_LOOKAHEAD */
-unsigned	*pNumBytes	/* Result: #Bytes to present
-				   to SK_RLMT_LOOKAHEAD */
+SK_U32		PortNum		/* receiving port */
+unsigned	PktLen		/* received packet's length */
+SK_BOOL		IsBc		/* Flag: packet is broadcast */
+unsigned	*pOffset	/* offs. of bytes to present to SK_RLMT_LOOKAHEAD */
+unsigned	*pNumBytes	/* #Bytes to present to SK_RLMT_LOOKAHEAD */
 #endif	/* 0 */
 
-
-#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortIdx,PacketLength,IsBc,pOffset,pNumBytes) { \
+#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \
 	SK_AC	*_pAC; \
-	SK_U32	_PortIdx; \
+	SK_U32	_PortNum; \
 	_pAC = (pAC); \
-	_PortIdx = (SK_U32)(PortIdx); \
-	_pAC->Rlmt.Port[_PortIdx].PacketsRx++; \
-	_pAC->Rlmt.Port[_PortIdx].PacketsPerTimeSlot++; \
-	if ((IsBc) && _pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS) { \
-		*(pOffset) = 6; \
-		*(pNumBytes) = 6; \
+	_PortNum = (SK_U32)(PortNum); \
+	/* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \
+	_pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \
+	if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \
+		*(pNumBytes) = 0; \
+	} \
+	else if (IsBc) { \
+		if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \
+			*(pNumBytes) = 6; \
+			*(pOffset) = 6; \
+		} \
+		else { \
+			*(pNumBytes) = 0; \
+		} \
 	} \
 	else { \
-		*(pOffset) = 0; \
-		if ((PacketLength) > SK_RLMT_MAX_TX_BUF_SIZE) { \
-			_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+		if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
 			*(pNumBytes) = 0; \
 		} \
 		else { \
 			*(pNumBytes) = 6; \
+			*(pOffset) = 0; \
 		} \
 	} \
 }
 
 #if 0
 SK_AC		*pAC		/* adapter context */
-SK_U32		PortIdx		/* receiving port */
+SK_U32		PortNum		/* receiving port */
 SK_U8		*pLaPacket,	/* received packet's data (points to pOffset) */
-SK_BOOL		IsBc		/* Flag: broadcast received */
-SK_BOOL		IsMc		/* Flag: multicast received */
-unsigned	*pForRlmt	/* Result: bits SK_RLMT_RX_RLMT,
-				   SK_RLMT_RX_PROTOCOL */
+SK_BOOL		IsBc		/* Flag: packet is broadcast */
+SK_BOOL		IsMc		/* Flag: packet is multicast */
+unsigned	*pForRlmt	/* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */
 SK_RLMT_LOOKAHEAD() expects *pNumBytes from
 packet offset *pOffset (s.a.) at *pLaPacket.
 
@@ -298,29 +321,28 @@
 BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler
 can trash unneeded parts of the if construction.
 #endif	/* 0 */
-#define SK_RLMT_LOOKAHEAD(pAC,PortIdx,pLaPacket,IsBc,IsMc,pForRlmt) { \
+
+#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \
 	SK_AC	*_pAC; \
-	SK_U32	_PortIdx; \
+	SK_U32	_PortNum; \
 	SK_U8	*_pLaPacket; \
 	_pAC = (pAC); \
-	_PortIdx = (SK_U32)(PortIdx); \
+	_PortNum = (SK_U32)(PortNum); \
 	_pLaPacket = (SK_U8 *)(pLaPacket); \
 	if (IsBc) {\
-		if (!SK_ADDR_EQUAL( \
-			_pLaPacket, \
-			_pAC->Addr.CurrentMacAddress.a)) { \
-			_pAC->Rlmt.Port[_PortIdx].BcTimeStamp = \
-				SkOsGetTime(_pAC); \
+		if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \
+			_PortNum].Net->NetNumber].CurrentMacAddress.a)) { \
+			_pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \
+			_pAC->Rlmt.CheckSwitch = SK_TRUE; \
 		} \
-		_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+		/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
 		*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
 	} \
 	else if (IsMc) { \
 		if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \
-			_pAC->Rlmt.Port[_PortIdx].BpduPacketsPerTimeSlot++; \
-			if (_pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { \
-				*(pForRlmt) = SK_RLMT_RX_RLMT | \
-					SK_RLMT_RX_PROTOCOL; \
+			_pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \
+			if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \
+				*(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \
 			} \
 			else { \
 				*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
@@ -330,18 +352,18 @@
 			*(pForRlmt) = SK_RLMT_RX_RLMT; \
 		} \
 		else { \
-			_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
 			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
 		} \
 	} \
 	else { \
 		if (SK_ADDR_EQUAL( \
 			_pLaPacket, \
-			_pAC->Addr.Port[_PortIdx].CurrentMacAddress.a)) { \
+			_pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \
 			*(pForRlmt) = SK_RLMT_RX_RLMT; \
 		} \
 		else { \
-			_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
 			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
 		} \
 	} \
@@ -350,107 +372,143 @@
 #ifdef SK_RLMT_FAST_LOOKAHEAD
 Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead.
 #endif	/* SK_RLMT_FAST_LOOKAHEAD */
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
 
 /* typedefs *******************************************************************/
 
+#ifdef SK_RLMT_MBUF_PRIVATE
+typedef struct s_RlmtMbuf {
+	some content
+} SK_RLMT_MBUF;
+#endif	/* SK_RLMT_MBUF_PRIVATE */
+
+
+#ifdef SK_LA_INFO
+typedef struct s_Rlmt_PacketInfo {
+	unsigned	PacketLength;			/* Length of packet. */
+	unsigned	PacketType;				/* Directed/Multicast/Broadcast. */
+} SK_RLMT_PINFO;
+#endif	/* SK_LA_INFO */
+
+
 typedef struct s_RootId {
-	SK_U8		Id[8];		/* Root Bridge Id. */
+	SK_U8		Id[8];					/* Root Bridge Id. */
 } SK_RLMT_ROOT_ID;
 
+
 typedef struct s_port {
 	SK_MAC_ADDR	CheckAddr;
 	SK_BOOL		SuspectTx;
 } SK_PORT_CHECK;
 
+
+typedef struct s_RlmtNet SK_RLMT_NET;
+
+
 typedef struct s_RlmtPort {
 
 /* ----- Public part (read-only) ----- */
 
-	SK_U8		PortState;	/* Current state of this port. */
+	SK_U8			PortState;				/* Current state of this port. */
 
 	/* For PNMI */
-
-	SK_BOOL		LinkDown;
-	SK_BOOL		PortDown;
-
-	SK_U64		TxHelloCts;
-	SK_U64		RxHelloCts;
-	SK_U64		TxSpHelloReqCts;
-	SK_U64		RxSpHelloCts;
+	SK_BOOL			LinkDown;
+	SK_BOOL			PortDown;
+	SK_U8			Align01;
+
+	SK_U32			PortNumber;				/* Number of port on adapter. */
+	SK_RLMT_NET *	Net;					/* Net port belongs to. */
+
+	SK_U64			TxHelloCts;
+	SK_U64			RxHelloCts;
+	SK_U64			TxSpHelloReqCts;
+	SK_U64			RxSpHelloCts;
 
 /* ----- Private part ----- */
 
-	SK_BOOL		PortStarted;		/* Port is started. */
-	SK_BOOL		PortNoRx;		/* NoRx for >= 1 time slot. */
-	SK_U32		CheckingState;		/* Checking State. */
-
-	SK_U64		PacketsRx;		/* Total packets received. */
-	SK_U32		PacketsPerTimeSlot;	/* Packets rxed between TOs. */
-	SK_U32		DataPacketsPerTimeSlot;	/* Data packets ... */
-#if 0
-	SK_U32		RlmtAcksPerTimeSlot;	/* RLMT Acks rxed in TS. */
-	SK_U32		RlmtChksPerTimeSlot;	/* RLMT Chks rxed in TS. */
-#endif	/* 0 */
-	SK_U32		BpduPacketsPerTimeSlot;	/* BPDU packets rxed in TS. */
-	SK_U64		BcTimeStamp;		/* Time of last BC receive. */
-	SK_U64		GuTimeStamp;		/* Time of entering GOING_UP. */
-
-	SK_TIMER	UpTimer;		/* Timer struct Link/Port up. */
-	SK_TIMER	DownRxTimer;		/* Timer struct down rx. */
-	SK_TIMER	DownTxTimer;		/* Timer struct down tx. */
-
-	SK_U8		Random[4];		/* Random value. */
-	unsigned	PortsChecked;		/* #ports checked. */
-	unsigned	PortsSuspect;		/* #ports checked that are s. */
+/*	SK_U64			PacketsRx; */				/* Total packets received. */
+	SK_U32			PacketsPerTimeSlot;		/* Packets rxed between TOs. */
+/*	SK_U32			DataPacketsPerTimeSlot; */	/* Data packets ... */
+	SK_U32			BpduPacketsPerTimeSlot;	/* BPDU packets rxed in TS. */
+	SK_U64			BcTimeStamp;			/* Time of last BC receive. */
+	SK_U64			GuTimeStamp;			/* Time of entering GOING_UP. */
+
+	SK_TIMER		UpTimer;				/* Timer struct Link/Port up. */
+	SK_TIMER		DownRxTimer;			/* Timer struct down rx. */
+	SK_TIMER		DownTxTimer;			/* Timer struct down tx. */
+
+	SK_U32			CheckingState;			/* Checking State. */
+
+	SK_ADDR_PORT *	AddrPort;
+
+	SK_U8			Random[4];				/* Random value. */
+	unsigned		PortsChecked;			/* #ports checked. */
+	unsigned		PortsSuspect;			/* #ports checked that are s. */
 	SK_PORT_CHECK	PortCheck[1];
 /*	SK_PORT_CHECK	PortCheck[SK_MAX_MACS - 1]; */
 
-	SK_BOOL		RootIdSet;
-	SK_RLMT_ROOT_ID	Root;			/* Root Bridge Id. */
+	SK_BOOL			PortStarted;			/* Port is started. */
+	SK_BOOL			PortNoRx;				/* NoRx for >= 1 time slot. */
+	SK_BOOL			RootIdSet;
+	SK_RLMT_ROOT_ID	Root;					/* Root Bridge Id. */
 } SK_RLMT_PORT;
 
-#ifdef SK_RLMT_MBUF_PRIVATE
-typedef struct s_RlmtMbuf {
-	some content
-} SK_RLMT_MBUF;
-#endif	/* SK_RLMT_MBUF_PRIVATE */
 
-#ifdef SK_LA_INFO
-typedef struct s_Rlmt_PacketInfo {
-	unsigned	PacketLength;	/* Length of packet. */
-	unsigned	PacketType;	/* Directed/Multicast/Broadcast. */
-} SK_RLMT_PINFO;
-#endif	/* SK_LA_INFO */
-
-typedef struct s_Rlmt {
+struct s_RlmtNet {
 
 /* ----- Public part (read-only) ----- */
 
-	SK_U8		RlmtState;		/* Current RLMT state. */
-	SK_RLMT_PORT	Port[SK_MAX_MACS];	/* Array of available ports. */
-	SK_U32		PrefPort;		/* Preferred port. */
+	SK_U32			NetNumber;			/* Number of net. */
+
+	SK_RLMT_PORT *	Port[SK_MAX_MACS];	/* Ports that belong to this net. */
+	SK_U32			NumPorts;			/* Number of ports. */
+	SK_U32			PrefPort;			/* Preferred port. */
 
 	/* For PNMI */
 
-	SK_U32		RlmtMode;		/* Check ... */
-	SK_U32		MacActive;		/* Active port. */
-	SK_U32		MacPreferred;		/* 0xFFFFFFFF: Automatic. */
+	SK_U32			RlmtMode;			/* Check ... */
+	SK_U32			ActivePort;			/* Active port. */
+	SK_U32			Preference;		/* 0xFFFFFFFF: Automatic. */
+
+	SK_U8			RlmtState;			/* Current RLMT state. */
+
+/* ----- Private part ----- */
+	SK_BOOL			RootIdSet;
+	SK_U16			Align01;
+
+	int				LinksUp;			/* #Links up. */
+	int				PortsUp;			/* #Ports up. */
+	SK_U32			TimeoutValue;		/* RLMT timeout value. */
+
+	SK_U32			CheckingState;		/* Checking State. */
+	SK_RLMT_ROOT_ID	Root;				/* Root Bridge Id. */
+
+	SK_TIMER		LocTimer;			/* Timer struct. */
+	SK_TIMER		SegTimer;			/* Timer struct. */
+};
+
+
+typedef struct s_Rlmt {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U32			NumNets;			/* Number of nets. */
+	SK_U32			NetsStarted;		/* Number of nets started. */
+	SK_RLMT_NET		Net[SK_MAX_NETS];	/* Array of available nets. */
+	SK_RLMT_PORT	Port[SK_MAX_MACS];	/* Array of available ports. */
 
 /* ----- Private part ----- */
+	SK_BOOL			CheckSwitch;
+	SK_U8			Align01;
+	SK_U16			Align02;
 
-	int		LinksUp;		/* #Links up. */
-	int		PortsUp;		/* #Ports up. */
-	SK_U32		TimeoutValue;		/* RLMT timeout value. */
-	SK_TIMER	LocTimer;		/* Timer struct. */
-
-	SK_U32		CheckingState;		/* Checking State. */
-	SK_BOOL		RootIdSet;
-	SK_RLMT_ROOT_ID	Root;			/* Root Bridge Id. */
-	SK_TIMER	SegTimer;		/* Timer struct. */
 } SK_RLMT;
 
+
 extern	SK_MAC_ADDR	BridgeMcAddr;
-extern	SK_MAC_ADDR     SkRlmtMcAddr;
+extern	SK_MAC_ADDR	SkRlmtMcAddr;
 
 /* function prototypes ********************************************************/
 
@@ -464,16 +522,7 @@
 extern	void	SkRlmtInit(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	int	Level);
-
-#ifdef SK_RLMT_SLOW_LOOKAHEAD
-extern	SK_BOOL	SkRlmtLookaheadPacket(
-	SK_AC		*pAC,
-	SK_U32		PortIdx,
-	SK_U8		*pLaPacket,
-	unsigned	PacketLength,
-	unsigned	LaLength);
-#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
+	int		Level);
 
 extern	int	SkRlmtEvent(
 	SK_AC		*pAC,
@@ -481,11 +530,11 @@
 	SK_U32		Event,
 	SK_EVPARA	Para);
 
-#else	/* defined(SK_KR_PROTO)) */
+#else	/* defined(SK_KR_PROTO) */
 
 /* Non-ANSI/C++ compliant function prototypes */
 
-xxxx	/* not supported yet - force error */
+#error KR-style function prototypes are not yet provided.
 
 #endif	/* defined(SK_KR_PROTO)) */
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/sktimer.h linux/drivers/net/sk98lin/h/sktimer.h
--- v2.4.6/linux/drivers/net/sk98lin/h/sktimer.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/sktimer.h	Wed Jul  4 11:50:39 2001
@@ -1,23 +1,32 @@
 /******************************************************************************
  *
  * Name:	sktimer.h
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.9 $
- * Date:	$Date: 1999/11/22 14:00:29 $
+ * Project:	Genesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.8 $
+ * Date:	$Date: 1998/09/08 08:48:02 $
  * Purpose:	Defines for the timer functions
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1989-1998 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	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; either version 2 of the License, or
- *	(at your option) any later version.
- *
+ *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
+ *	The copyright notice above does not evidence any
+ *	actual or intended publication of such source code.
+ *
+ *	This Module contains Proprietary Information of SysKonnect
+ *	and should be treated as Confidential.
+ *
+ *	The information in this file is provided for the exclusive use of
+ *	the licensees of SysKonnect.
+ *	Such users have the right to use, modify, and incorporate this code
+ *	into products for purposes authorized by the license agreement
+ *	provided they include this notice and the associated copyright notice
+ *	with any such product.
  *	The information in this file is provided "AS IS" without warranty.
  *
  ******************************************************************************/
@@ -27,9 +36,6 @@
  * History:
  *
  *	$Log: sktimer.h,v $
- *	Revision 1.9  1999/11/22 14:00:29  cgoos
- *	Changed license header to GPL.
- *	
  *	Revision 1.8  1998/09/08 08:48:02  gklug
  *	add: init level handling
  *	
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skversion.h linux/drivers/net/sk98lin/h/skversion.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skversion.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sk98lin/h/skversion.h	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Name:	version.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.1 $
+ * Date:	$Date: 2001/03/06 09:25:00 $
+ * Purpose:	SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skversion.h,v $
+ *	Revision 1.1  2001/03/06 09:25:00  mlindner
+ *	first version
+ *	
+ *	
+ *
+ ******************************************************************************/
+ 
+ 
+static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect GmbH.";
+static const char SysKonnectBuildNumber[] =
+	"@(#)SK-BUILD: 4.06 PL: 01"; 
+
+#define BOOT_STRING	"sk98lin: Network Device Driver v4.06\n" \
+			"Copyright (C) 2000-2001 SysKonnect GmbH."
+
+#define VER_STRING	"4.06"
+
+
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skvpd.h linux/drivers/net/sk98lin/h/skvpd.h
--- v2.4.6/linux/drivers/net/sk98lin/h/skvpd.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skvpd.h	Wed Jul  4 11:50:39 2001
@@ -2,15 +2,15 @@
  *
  * Name:	skvpd.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.10 $
- * Date:	$Date: 2000/08/10 11:29:07 $
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 1999/11/22 14:02:27 $
  * Purpose:	Defines and Macros for VPD handling
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
+ *	(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
@@ -27,12 +27,6 @@
  * History:
  *
  *	$Log: skvpd.h,v $
- *	Revision 1.10  2000/08/10 11:29:07  rassmann
- *	Editorial changes.
- *	Preserving 32-bit alignment in structs for the adapter context.
- *	Removed unused function VpdWriteDword() (#if 0).
- *	Made VpdReadKeyword() available for SKDIAG only.
- *	
  *	Revision 1.9  1999/11/22 14:02:27  cgoos
  *	Changed license header to GPL.
  *	
@@ -121,42 +115,40 @@
 
 /* VPD status */
 	/* bit 7..1 reserved */
-#define VPD_VALID	(1<<0)	/* VPD data buffer, vpd_free_ro, */
-							/* and vpd_free_rw valid	 */
+#define VPD_VALID	(1<<0)		/* VPD data buffer, vpd_free_ro, */
+					/* and vpd_free_rw valid	 */
 
 /*
  * VPD structs
  */
 typedef	struct s_vpd_status {
-	unsigned short	Align01;			/* Alignment */
-	unsigned short	vpd_status;			/* VPD status, description see above */
-	int				vpd_free_ro;		/* unused bytes in read only area */
-	int				vpd_free_rw;		/* bytes available in read/write area */
+	unsigned short	vpd_status ;	/* VPD status, description see above */
+	int		vpd_free_ro ;	/* unused bytes in read only area */
+	int		vpd_free_rw ;	/* bytes available in read/write area */
 } SK_VPD_STATUS;
 
 typedef	struct s_vpd {
-	SK_VPD_STATUS	v;					/* VPD status structure */
-	char			vpd_buf[VPD_SIZE];	/* VPD buffer */
+	SK_VPD_STATUS	v ;			/* VPD status structure */
+	char		vpd_buf[VPD_SIZE] ;	/* VPD buffer */
 } SK_VPD;
 
 typedef	struct s_vpd_para {
-	unsigned int	p_len;	/* parameter length */
-	char			*p_val;	/* points to the value */
+	unsigned int	p_len ;		/* parameter length */
+	char		*p_val ;	/* points to the value */
 } SK_VPD_PARA;
 
 /*
  * structure of Large Resource Type Identifiers
  */
-
-/* was removed because of alignment problems */
+/* was removed, because of alignment problems */
 
 /*
  * sturcture of VPD keywords
  */
 typedef	struct s_vpd_key {
-	char			p_key[2];	/* 2 bytes ID string */
-	unsigned char	p_len;		/* 1 byte length */
-	char			p_val;		/* start of the value string */
+	char		p_key[2] ;	/* 2 bytes ID string */
+	unsigned char	p_len ;		/* 1 byte length */
+	char		p_val ;		/* start of the value string */
 } SK_VPD_KEY;
 
 
@@ -180,39 +172,39 @@
 #define VPD_IN32(pAC,IoC,Addr,pVal)	SK_IN32(IoC,PCI_C(Addr),pVal)
 #endif	/* VPD_DO_IO */
 #else	/* SKDIAG */
-#define VPD_OUT8(pAC,Ioc,Addr,Val) {			\
+#define VPD_OUT8(pAC,Ioc,Addr,Val) {				\
 		if ((pAC)->DgT.DgUseCfgCycle)			\
-			SkPciWriteCfgByte(pAC,Addr,Val);	\
-		else									\
+			SkPciWriteCfgByte(pAC,Addr,Val) ;	\
+		else						\
 			SK_OUT8(pAC,PCI_C(Addr),Val);		\
 		}
-#define VPD_OUT16(pAC,Ioc,Addr,Val) {			\
+#define VPD_OUT16(pAC,Ioc,Addr,Val) {				\
 		if ((pAC)->DgT.DgUseCfgCycle)			\
-			SkPciWriteCfgWord(pAC,Addr,Val);	\
+			SkPciWriteCfgWord(pAC,Addr,Val) ;	\
 		else						\
 			SK_OUT16(pAC,PCI_C(Addr),Val);		\
 		}
-#define VPD_OUT32(pAC,Ioc,Addr,Val) {			\
+#define VPD_OUT32(pAC,Ioc,Addr,Val) {				\
 		if ((pAC)->DgT.DgUseCfgCycle)			\
-			SkPciWriteCfgDWord(pAC,Addr,Val);	\
+			SkPciWriteCfgDWord(pAC,Addr,Val) ;	\
 		else						\
 			SK_OUT32(pAC,PCI_C(Addr),Val); 		\
 		}
-#define VPD_IN8(pAC,Ioc,Addr,pVal) {			\
+#define VPD_IN8(pAC,Ioc,Addr,pVal) {				\
 		if ((pAC)->DgT.DgUseCfgCycle) 			\
-			SkPciReadCfgByte(pAC,Addr,pVal);	\
+			SkPciReadCfgByte(pAC,Addr,pVal) ;	\
 		else						\
 			SK_IN8(pAC,PCI_C(Addr),pVal); 		\
 		}
-#define VPD_IN16(pAC,Ioc,Addr,pVal) {			\
+#define VPD_IN16(pAC,Ioc,Addr,pVal) {				\
 		if ((pAC)->DgT.DgUseCfgCycle) 			\
-			SkPciReadCfgWord(pAC,Addr,pVal);	\
+			SkPciReadCfgWord(pAC,Addr,pVal) ;	\
 		else						\
 			SK_IN16(pAC,PCI_C(Addr),pVal); 		\
 		}
-#define VPD_IN32(pAC,Ioc,Addr,pVal) {			\
+#define VPD_IN32(pAC,Ioc,Addr,pVal) {				\
 		if ((pAC)->DgT.DgUseCfgCycle)			\
-			SkPciReadCfgDWord(pAC,Addr,pVal);	\
+			SkPciReadCfgDWord(pAC,Addr,pVal) ;	\
 		else						\
 			SK_IN32(pAC,PCI_C(Addr),pVal);		\
 		}
@@ -221,52 +213,50 @@
 /* function prototypes ********************************************************/
 
 #ifndef	SK_KR_PROTO
-#ifdef SKDIAG
 extern SK_U32	VpdReadDWord(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
-	int			addr);
-#endif	/* SKDIAG */
+	int		addr) ;
 
 extern int	VpdSetupPara(
 	SK_AC		*pAC,
 	char		*key,
 	char		*buf,
-	int			len,
-	int			type,
-	int			op);
+	int		len,
+	int		type,
+	int		op) ;
 
 extern SK_VPD_STATUS	*VpdStat(
 	SK_AC		*pAC,
-	SK_IOC		IoC);
+	SK_IOC		IoC) ;
 
 extern int	VpdKeys(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	char		*buf,
-	int			*len,
-	int			*elements);
+	int		*len,
+	int		*elements) ;
 
 extern int	VpdRead(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	char		*key,
 	char		*buf,
-	int			*len);
+	int		*len) ;
 
 extern	SK_BOOL	VpdMayWrite(
-	char		*key);
+	char		*key) ;
 
 extern int	VpdWrite(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	char		*key,
-	char		*buf);
+	char		*buf) ;
 
 extern int	VpdDelete(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
-	char		*key);
+	char		*key) ;
 
 extern int	VpdUpdate(
 	SK_AC		*pAC,
@@ -275,34 +265,34 @@
 extern void	VpdErrLog(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
-	char		*msg);
+	char		*msg) ;
 
 #ifdef	SKDIAG
 extern int	VpdReadBlock(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	char		*buf,
-	int			addr,
-	int			len);
+	int		addr,
+	int		len) ;
 
 extern int	VpdWriteBlock(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	char		*buf,
-	int			addr,
-	int			len);
+	int		addr,
+	int		len) ;
 #endif	/* SKDIAG */
 #else	/* SK_KR_PROTO */
-extern SK_U32	VpdReadDWord();
-extern int	VpdSetupPara();
-extern SK_VPD_STATUS	*VpdStat();
-extern int	VpdKeys();
-extern int	VpdRead();
-extern SK_BOOL	VpdMayWrite();
-extern int	VpdWrite();
-extern int	VpdDelete();
-extern int	VpdUpdate();
-extern void	VpdErrLog();
+extern SK_U32	VpdReadDWord() ;
+extern int	VpdSetupPara() ;
+extern SK_VPD_STATUS	*VpdStat() ;
+extern int	VpdKeys() ;
+extern int	VpdRead() ;
+extern SK_BOOL	VpdMayWrite() ;
+extern int	VpdWrite() ;
+extern int	VpdDelete() ;
+extern int	VpdUpdate() ;
+extern void	VpdErrLog() ;
 #endif	/* SK_KR_PROTO */
 
 #endif	/* __INC_SKVPD_H_ */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/xmac_ii.h linux/drivers/net/sk98lin/h/xmac_ii.h
--- v2.4.6/linux/drivers/net/sk98lin/h/xmac_ii.h	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/h/xmac_ii.h	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	xmac_ii.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.27 $
- * Date:	$Date: 2000/05/17 11:00:46 $
+ * Version:	$Revision: 1.28 $
+ * Date:	$Date: 2000/11/09 12:32:49 $
  * Purpose:	Defines and Macros for XaQti's Gigabit Ethernet Controller
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2000 SysKonnect 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
@@ -27,6 +26,9 @@
  * History:
  *
  *	$Log: xmac_ii.h,v $
+ *	Revision 1.28  2000/11/09 12:32:49  rassmann
+ *	Renamed variables.
+ *	
  *	Revision 1.27  2000/05/17 11:00:46  malthoff
  *	Add bit for enable/disable power management in BCOM chip.
  *	
@@ -145,40 +147,40 @@
  * Note:	NA reg	= Network Address e.g DA, SA etc.
  *
  */
-#define XM_MMU_CMD	0x0000	/* 16 bit r/w	MMU Command Register */
+#define XM_MMU_CMD	0x0000		/* 16 bit r/w	MMU Command Register */
 	/* 0x0004:		reserved */
-#define XM_POFF		0x0008	/* 32 bit r/w	Packet Offset Register */
-#define XM_BURST	0x000c	/* 32 bit r/w	Burst Register for half duplex*/
+#define XM_POFF		0x0008		/* 32 bit r/w	Packet Offset Register */
+#define XM_BURST	0x000c		/* 32 bit r/w	Burst Register for half duplex*/
 #define XM_1L_VLAN_TAG	0x0010	/* 16 bit r/w	One Level VLAN Tag ID */
 #define XM_2L_VLAN_TAG	0x0014	/* 16 bit r/w	Two Level VLAN Tag ID */
 	/* 0x0018 - 0x001e:	reserved */
-#define XM_TX_CMD	0x0020	/* 16 bit r/w	Transmit Command Register */
+#define XM_TX_CMD	0x0020		/* 16 bit r/w	Transmit Command Register */
 #define	XM_TX_RT_LIM	0x0024	/* 16 bit r/w	Transmit Retry Limit Register */
-#define XM_TX_STIME	0x0028	/* 16 bit r/w	Transmit Slottime Register */
-#define XM_TX_IPG	0x002c	/* 16 bit r/w	Transmit Inter Packet Gap */
-#define XM_RX_CMD	0x0030	/* 16 bit r/w	Receive Command Register */
-#define XM_PHY_ADDR	0x0034	/* 16 bit r/w	PHY Address Register */
-#define	XM_PHY_DATA	0x0038	/* 16 bit r/w	PHY Data Register */
+#define XM_TX_STIME	0x0028		/* 16 bit r/w	Transmit Slottime Register */
+#define XM_TX_IPG	0x002c		/* 16 bit r/w	Transmit Inter Packet Gap */
+#define XM_RX_CMD	0x0030		/* 16 bit r/w	Receive Command Register */
+#define XM_PHY_ADDR	0x0034		/* 16 bit r/w	PHY Address Register */
+#define	XM_PHY_DATA	0x0038		/* 16 bit r/w	PHY Data Register */
 	/* 0x003c: 		reserved */
-#define XM_GP_PORT	0x0040	/* 32 bit r/w	General Purpose Port Register */
-#define XM_IMSK		0x0044	/* 16 bit r/w	Interrupt Mask Register */
-#define XM_ISRC		0x0048	/* 16 bit ro	Interrupt Status Register */
-#define XM_HW_CFG	0x004c	/* 16 bit r/w	Hardware Config Register */
+#define XM_GP_PORT	0x0040		/* 32 bit r/w	General Purpose Port Register */
+#define XM_IMSK		0x0044		/* 16 bit r/w	Interrupt Mask Register */
+#define XM_ISRC		0x0048		/* 16 bit ro	Interrupt Status Register */
+#define XM_HW_CFG	0x004c		/* 16 bit r/w	Hardware Config Register */
 	/* 0x0050 - 0x005e:	reserved */
-#define XM_TX_LO_WM	0x0060	/* 16 bit r/w	Tx FIFO Low Water Mark */
-#define XM_TX_HI_WM	0x0062	/* 16 bit r/w	Tx FIFO High Water Mark */
-#define XM_TX_THR	0x0064	/* 16 bit r/w	Tx Request Threshold */
-#define	XM_HT_THR	0x0066	/* 16 bit r/w	Host Request Threshold */
-#define	XM_PAUSE_DA	0x0068	/* NA reg r/w	Pause Destination Address */
+#define XM_TX_LO_WM	0x0060		/* 16 bit r/w	Tx FIFO Low Water Mark */
+#define XM_TX_HI_WM	0x0062		/* 16 bit r/w	Tx FIFO High Water Mark */
+#define XM_TX_THR	0x0064		/* 16 bit r/w	Tx Request Threshold */
+#define	XM_HT_THR	0x0066		/* 16 bit r/w	Host Request Threshold */
+#define	XM_PAUSE_DA	0x0068		/* NA reg r/w	Pause Destination Address */
 	/* 0x006e: 		reserved */
-#define XM_CTL_PARA	0x0070	/* 32 bit r/w	Control Parameter Register */
+#define XM_CTL_PARA	0x0070		/* 32 bit r/w	Control Parameter Register */
 #define XM_MAC_OPCODE	0x0074	/* 16 bit r/w	Opcode for MAC control frames */
 #define XM_MAC_PTIME	0x0076	/* 16 bit r/w	Pause time for MAC ctrl frames*/
-#define XM_TX_STAT	0x0078	/* 32 bit ro	Tx Status LIFO Register */
+#define XM_TX_STAT	0x0078		/* 32 bit ro	Tx Status LIFO Register */
 
 	/* 0x0080 - 0x00fc:	16 NA reg r/w	Exakt Match Address Registers */
 	/* 				use the XM_EMX() macro to address */
-#define XM_EXM_START	0x0080		/* r/w	Start Address of the EXM Regs */
+#define XM_EXM_START	0x0080	/* r/w	Start Address of the EXM Regs */
 
 	/*
 	 * XM_EXM(Reg)
@@ -191,18 +193,18 @@
 	 */
 #define XM_EXM(Reg)	(XM_EXM_START + ((Reg) << 3))
 
-#define XM_SRC_CHK	0x0100	/* NA reg r/w	Source Check Address Register */
-#define XM_SA		0x0108	/* NA reg r/w	Station Address Register */
-#define XM_HSM		0x0110	/* 64 bit r/w	Hash Match Address Registers */
-#define XM_RX_LO_WM	0x0118	/* 16 bit r/w	Receive Low Water Mark */
-#define XM_RX_HI_WM	0x011a	/* 16 bit r/w	Receive High Water Mark */
-#define XM_RX_THR	0x011c	/* 32 bit r/w	Receive Request Threshold */
-#define XM_DEV_ID	0x0120	/* 32 bit ro	Device ID Register */
-#define XM_MODE		0x0124	/* 32 bit r/w	Mode Register */
-#define XM_LSA		0x0128	/* NA reg ro	Last Source Register */
+#define XM_SRC_CHK		0x0100	/* NA reg r/w	Source Check Address Register */
+#define XM_SA			0x0108	/* NA reg r/w	Station Address Register */
+#define XM_HSM			0x0110	/* 64 bit r/w	Hash Match Address Registers */
+#define XM_RX_LO_WM		0x0118	/* 16 bit r/w	Receive Low Water Mark */
+#define XM_RX_HI_WM		0x011a	/* 16 bit r/w	Receive High Water Mark */
+#define XM_RX_THR		0x011c	/* 32 bit r/w	Receive Request Threshold */
+#define XM_DEV_ID		0x0120	/* 32 bit ro	Device ID Register */
+#define XM_MODE			0x0124	/* 32 bit r/w	Mode Register */
+#define XM_LSA			0x0128	/* NA reg ro	Last Source Register */
 	/* 0x012e:		reserved */
-#define XM_TS_READ	0x0130	/* 32 bit ro	TimeStamp Read Regeister */
-#define XM_TS_LOAD	0x0134	/* 32 bit ro	TimeStamp Load Value */
+#define XM_TS_READ		0x0130	/* 32 bit ro	TimeStamp Read Regeister */
+#define XM_TS_LOAD		0x0134	/* 32 bit ro	TimeStamp Load Value */
 	/* 0x0138 - 0x01fe:	reserved */
 #define XM_STAT_CMD	0x0200	/* 16 bit r/w	Statistics Command Register */
 #define	XM_RX_CNT_EV	0x0204	/* 32 bit ro	Rx Counter Event Register */
@@ -210,13 +212,13 @@
 #define XM_RX_EV_MSK	0x020c	/* 32 bit r/w	Rx Counter Event Mask */
 #define XM_TX_EV_MSK	0x0210	/* 32 bit r/w	Tx Counter Event Mask */
 	/* 0x0204 - 0x027e:	reserved */
-#define XM_TXF_OK	0x0280	/* 32 bit ro	Frames Transmitted OK Conuter */
+#define XM_TXF_OK		0x0280	/* 32 bit ro	Frames Transmitted OK Conuter */
 #define XM_TXO_OK_HI	0x0284	/* 32 bit ro	Octets Transmitted OK High Cnt*/
 #define XM_TXO_OK_LO	0x0288	/* 32 bit ro	Octets Transmitted OK Low Cnt */
 #define XM_TXF_BC_OK	0x028c	/* 32 bit ro	Broadcast Frames Xmitted OK */
 #define XM_TXF_MC_OK	0x0290	/* 32 bit ro	Multicast Frames Xmitted OK */
 #define XM_TXF_UC_OK	0x0294	/* 32 bit ro	Unicast Frames Xmitted OK */
-#define XM_TXF_LONG	0x0298	/* 32 bit ro	Tx Long Frame Counter */
+#define XM_TXF_LONG		0x0298	/* 32 bit ro	Tx Long Frame Counter */
 #define XM_TXE_BURST	0x029c	/* 32 bit ro	Tx Burst Event Counter */
 #define XM_TXF_MPAUSE	0x02a0	/* 32 bit ro	Tx Pause MAC Ctrl Frame Cnt */
 #define XM_TXF_MCTRL	0x02a4	/* 32 bit ro	Tx MAC Ctrl Frame Counter */
@@ -224,20 +226,20 @@
 #define XM_TXF_MUL_COL	0x02ac	/* 32 bit ro	Tx Multiple Collision Counter */
 #define XM_TXF_ABO_COL	0x02b0	/* 32 bit ro	Tx aborted due to Exessive Col*/
 #define XM_TXF_LAT_COL	0x02b4	/* 32 bit ro	Tx Late Collision Counter */
-#define XM_TXF_DEF	0x02b8	/* 32 bit ro	Tx Deferred Frame Counter */
+#define XM_TXF_DEF		0x02b8	/* 32 bit ro	Tx Deferred Frame Counter */
 #define XM_TXF_EX_DEF	0x02bc	/* 32 bit ro	Tx Excessive Deferall Counter */
 #define XM_TXE_FIFO_UR	0x02c0	/* 32 bit ro	Tx FIFO Underrun Event Cnt */
 #define XM_TXE_CS_ERR	0x02c4	/* 32 bit ro	Tx Carrier Sence Error Cnt */
-#define XM_TXP_UTIL	0x02c8	/* 32 bit ro	Tx Utilization in % */
+#define XM_TXP_UTIL		0x02c8	/* 32 bit ro	Tx Utilization in % */
 	/* 0x02cc - 0x02ce:	reserved */
-#define XM_TXF_64B	0x02d0	/* 32 bit ro	64 Byte Tx Frame Counter */
-#define XM_TXF_127B	0x02d4	/* 32 bit ro	65-127 Byte Tx Frame Counter */
-#define XM_TXF_255B	0x02d8	/* 32 bit ro	128-255 Byte Tx Frame Counter */
-#define XM_TXF_511B	0x02dc	/* 32 bit ro	256-511 Byte Tx Frame Counter */
+#define XM_TXF_64B		0x02d0	/* 32 bit ro	64 Byte Tx Frame Counter */
+#define XM_TXF_127B		0x02d4	/* 32 bit ro	65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B		0x02d8	/* 32 bit ro	128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B		0x02dc	/* 32 bit ro	256-511 Byte Tx Frame Counter */
 #define XM_TXF_1023B	0x02e0	/* 32 bit ro	512-1023 Byte Tx Frame Counter*/
 #define XM_TXF_MAX_SZ	0x02e4	/* 32 bit ro	1024-MaxSize Byte Tx Frame Cnt*/
 	/* 0x02e8 - 0x02fe:	reserved */
-#define XM_RXF_OK	0x0300	/* 32 bit ro	Frames Received OK */
+#define XM_RXF_OK		0x0300	/* 32 bit ro	Frames Received OK */
 #define XM_RXO_OK_HI	0x0304	/* 32 bit ro	Octets Received OK High Cnt */
 #define XM_RXO_OK_LO	0x0308	/* 32 bit ro	Octets Received OK Low Counter*/
 #define XM_RXF_BC_OK	0x030c	/* 32 bit ro	Broadcast Frames Received OK */
@@ -256,17 +258,17 @@
 #define XM_RXF_LEN_ERR	0x0340	/* 32 bit ro	Rx in Range Length Error */
 #define XM_RXE_SYM_ERR	0x0344	/* 32 bit ro	Rx Symbol Error Counter */
 #define XM_RXE_SHT_ERR	0x0348	/* 32 bit ro	Rx Short Event Error Cnt */
-#define XM_RXE_RUNT	0x034c	/* 32 bit ro	Rx Runt Event Counter */
+#define XM_RXE_RUNT		0x034c	/* 32 bit ro	Rx Runt Event Counter */
 #define XM_RXF_LNG_ERR	0x0350	/* 32 bit ro	Rx Frame too Long Error Cnt */
 #define XM_RXF_FCS_ERR	0x0354	/* 32 bit ro	Rx Frame Check Seq. Error Cnt */
 	/* 0x0358 - 0x035a:	reserved */
 #define XM_RXF_CEX_ERR	0x035c	/* 32 bit ro	Rx Carrier Ext Error Frame Cnt*/
-#define XM_RXP_UTIL	0x0360	/* 32 bit ro	Rx Utilization in % */
+#define XM_RXP_UTIL		0x0360	/* 32 bit ro	Rx Utilization in % */
 	/* 0x0364 - 0x0366:	reserved */
-#define XM_RXF_64B	0x0368	/* 32 bit ro	64 Byte Rx Frame Counter */
-#define XM_RXF_127B	0x036c	/* 32 bit ro	65-127 Byte Rx Frame Counter */
-#define XM_RXF_255B	0x0370	/* 32 bit ro	128-255 Byte Rx Frame Counter */
-#define XM_RXF_511B	0x0374	/* 32 bit ro	256-511 Byte Rx Frame Counter */
+#define XM_RXF_64B		0x0368	/* 32 bit ro	64 Byte Rx Frame Counter */
+#define XM_RXF_127B		0x036c	/* 32 bit ro	65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B		0x0370	/* 32 bit ro	128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B		0x0374	/* 32 bit ro	256-511 Byte Rx Frame Counter */
 #define XM_RXF_1023B	0x0378	/* 32 bit ro	512-1023 Byte Rx Frame Counter*/
 #define XM_RXF_MAX_SZ	0x037c	/* 32 bit ro	1024-MaxSize Byte Rx Frame Cnt*/
 	/* 0x02e8 - 0x02fe:	reserved */
@@ -277,19 +279,19 @@
  * XMAC Bit Definitions
  *
  * If the bit access behaviour differs from the register access behaviour
- * (r/w, ro) this is documented after the bit number. The following bit
+ * (r/w, ro) this is docomented after the bit number. The following bit
  * access behaviours are used:
  *	(sc)	self clearing
  *	(ro)	read only
  */
 
 /*	XM_MMU_CMD	16 bit r/w	MMU Comamnd Register */
-				/* Bit 15..13:	reserved */
+								/* Bit 15..13:	reserved */
 #define XM_MMU_PHY_RDY	(1<<12)	/* Bit 12:	PHY Read Ready */
 #define XM_MMU_PHY_BUSY	(1<<11)	/* Bit 11:	PHY Busy */
 #define XM_MMU_IGN_PF	(1<<10)	/* Bit 10:	Ignore Pause Frame */
 #define XM_MMU_MAC_LB	(1<<9)	/* Bit	9:	Enable MAC Loopback */
-				/* Bit	8:	reserved */
+								/* Bit	8:	reserved */
 #define XM_MMU_FRC_COL	(1<<7)	/* Bit	7:	Force Collision */
 #define XM_MMU_SIM_COL	(1<<6)	/* Bit	6:	Simulate Collision */
 #define XM_MMU_NO_PRE	(1<<5)	/* Bit	5:	No MDIO Preamble */
@@ -301,8 +303,8 @@
 
 
 /*	XM_TX_CMD	16 bit r/w	Transmit Command Register */
-				/* Bit 15..7:	reserved */
-#define XM_TX_BK2BK	(1<<6)	/* Bit	6:	Ignor Carrier Sense (tx Bk2Bk)*/
+								/* Bit 15..7:	reserved */
+#define XM_TX_BK2BK		(1<<6)	/* Bit	6:	Ignor Carrier Sense (tx Bk2Bk)*/
 #define XM_TX_ENC_BYP	(1<<5)	/* Bit	5:	Set Encoder in Bypass Mode */
 #define XM_TX_SAM_LINE	(1<<4)	/* Bit	4: (sc)	Start utilization calculation */
 #define XM_TX_NO_GIG_MD	(1<<3)	/* Bit	3:	Disable Carrier Extension */
@@ -312,28 +314,28 @@
 
 
 /*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
-				/* Bit 15..5:	reserved */
+								/* Bit 15..5:	reserved */
 #define	XM_RT_LIM_MSK	0x1f	/* Bit	4..0:	Tx Retry Limit */
 
 
 /*	XM_TX_STIME	16 bit r/w	Transmit Slottime Register */
-				/* Bit 15..7:	reserved */
+								/* Bit 15..7:	reserved */
 #define XM_STIME_MSK	0x7f	/* Bit	6..0:	Tx Slottime bits */
 
 
 /*	XM_TX_IPG	16 bit r/w	Transmit Inter Packet Gap */
-				/* Bit 15..8:	reserved */
-#define XM_IPG_MSK	0xff	/* Bit	7..0:	IPG value bits */
+								/* Bit 15..8:	reserved */
+#define XM_IPG_MSK		0xff	/* Bit	7..0:	IPG value bits */
 
 
 /*	XM_RX_CMD	16 bit r/w	Receive Command Register */
-				/* Bit 15..9:	reserved */
+								/* Bit 15..9:	reserved */
 #define XM_RX_LENERR_OK (1<<8)	/* Bit	8	don't set Rx Err bit for */
-				/*		inrange error packets */
+								/*		inrange error packets */
 #define XM_RX_BIG_PK_OK	(1<<7)	/* Bit	7	don't set Rx Err bit for */
-				/*		jumbo packets */
+								/*		jumbo packets */
 #define XM_RX_IPG_CAP	(1<<6)	/* Bit	6	repl. type field with IPG */
-#define XM_RX_TP_MD	(1<<5)	/* Bit	5:	Enable transparent Mode */
+#define XM_RX_TP_MD		(1<<5)	/* Bit	5:	Enable transparent Mode */
 #define XM_RX_STRIP_FCS	(1<<4)	/* Bit	4:	Enable FCS Stripping */
 #define XM_RX_SELF_RX	(1<<3)	/* Bit	3: 	Enable Rx of own packets */
 #define XM_RX_SAM_LINE	(1<<2)	/* Bit	2: (sc)	Start utilization calculation */
@@ -342,24 +344,24 @@
 
 
 /*	XM_PHY_ADDR	16 bit r/w	PHY Address Register */
-				/* Bit 15..5:	reserved */
+								/* Bit 15..5:	reserved */
 #define	XM_PHY_ADDR_SZ	0x1f	/* Bit	4..0:	PHY Address bits */
 
 
 /*	XM_GP_PORT	32 bit r/w	General Purpose Port Register */
-				/* Bit 31..7:	reserved */
-#define	XM_GP_ANIP	(1L<<6)	/* Bit	6: (ro)	Auto Negotiation in Progress */
+								/* Bit 31..7:	reserved */
+#define	XM_GP_ANIP		(1L<<6)	/* Bit	6: (ro)	Auto Negotiation in Progress */
 #define XM_GP_FRC_INT	(1L<<5)	/* Bit	5: (sc)	Force Interrupt */
-				/* Bit	4:	reserved */
+								/* Bit	4:	reserved */
 #define XM_GP_RES_MAC	(1L<<3)	/* Bit	3: (sc)	Reset MAC and FIFOs */
 #define XM_GP_RES_STAT	(1L<<2)	/* Bit	2: (sc)	Reset the statistics module */
-				/* Bit	1:	reserved */
+								/* Bit	1:	reserved */
 #define XM_GP_INP_ASS	(1L<<0)	/* Bit	0: (ro) GP Input Pin asserted */
 
 
 /*	XM_IMSK		16 bit r/w	Interrupt Mask Register */
 /*	XM_ISRC		16 bit ro	Interrupt Status Register */
-				/* Bit 15:	reserved */
+								/* Bit 15:	reserved */
 #define XM_IS_LNK_AE	(1<<14) /* Bit 14:	Link Asynchronous Event */
 #define XM_IS_TX_ABORT	(1<<13) /* Bit 13:	Transmit Abort, late Col. etc */
 #define XM_IS_FRC_INT	(1<<12) /* Bit 12:	Force INT bit set in GP */
@@ -367,7 +369,7 @@
 #define XM_IS_LIPA_RC	(1<<10)	/* Bit 10:	Link Partner requests config */
 #define XM_IS_RX_PAGE	(1<<9)	/* Bit	9:	Page Received */
 #define XM_IS_TX_PAGE	(1<<8)	/* Bit	8:	Next Page Loaded for Transmit */
-#define XM_IS_AND	(1<<7)	/* Bit	7:	Auto Negotiation Done */
+#define XM_IS_AND		(1<<7)	/* Bit	7:	Auto Negotiation Done */
 #define XM_IS_TSC_OV	(1<<6)	/* Bit	6:	Time Stamp Counter Overflow */
 #define XM_IS_RXC_OV	(1<<5)	/* Bit	5:	Rx Counter Event Overflow */
 #define XM_IS_TXC_OV	(1<<4)	/* Bit	4:	Tx Counter Event Overflow */
@@ -377,42 +379,41 @@
 #define XM_IS_RX_COMP	(1<<0)	/* Bit	0:	Frame Rx Complete */
 
 #define XM_DEF_MSK	(~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\
-			XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV |\
-			XM_IS_TXF_UR))
+			XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR))
 
 
 /*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
-				/* Bit 15.. 4:	reserved */
+								/* Bit 15.. 4:	reserved */
 #define	XM_HW_GEN_EOP	(1<<3)	/* Bit	3:	generate End of Packet pulse */
 #define XM_HW_COM4SIG	(1<<2)	/* Bit	2:	use Comma Detect for Sig. Det.*/
-				/* Bit	1:	reserved */
+								/* Bit	1:	reserved */
 #define XM_HW_GMII_MD	(1<<0)	/* Bit	0:	GMII Interface selected */
 
 
 /*	XM_TX_LO_WM	16 bit r/w	Tx FIFO Low Water Mark */
 /*	XM_TX_HI_WM	16 bit r/w	Tx FIFO High Water Mark */
-				/* Bit 15..10	reserved */
+								/* Bit 15..10	reserved */
 #define	XM_TX_WM_MSK	0x01ff	/* Bit	9.. 0	Tx FIFO Watermark bits */
 
 /*	XM_TX_THR	16 bit r/w	Tx Request Threshold */
 /*	XM_HT_THR	16 bit r/w	Host Request Threshold */
 /*	XM_RX_THR	16 bit r/w	Receive Request Threshold */
-				/* Bit 15..11	reserved */
-#define	XM_THR_MSK	0x03ff	/* Bit 10.. 0	Tx FIFO Watermark bits */
+								/* Bit 15..11	reserved */
+#define	XM_THR_MSK		0x03ff	/* Bit 10.. 0	Tx FIFO Watermark bits */
 
 
 /*	XM_TX_STAT	32 bit ro	Tx Status LIFO Register */
-#define XM_ST_VALID	(1UL<<31)	/* Bit 31:	Status Valid */
+#define XM_ST_VALID		(1UL<<31)	/* Bit 31:	Status Valid */
 #define XM_ST_BYTE_CNT	(0x3fffL<<17)	/* Bit 30..17:	Tx frame Length */
 #define XM_ST_RETRY_CNT	(0x1fL<<12)	/* Bit 16..12:	Retry Count */
 #define XM_ST_EX_COL	(1L<<11)	/* Bit 11:	Excessive Collisions */
 #define XM_ST_EX_DEF	(1L<<10)	/* Bit 10:	Excessive Deferral */
-#define XM_ST_BURST	(1L<<9)		/* Bit	9:	p. xmitted in burst md*/
-#define XM_ST_DEFER	(1L<<8)		/* Bit	8:	packet was defered */
-#define XM_ST_BC	(1L<<7)		/* Bit	7:	Broadcast packet */
-#define XM_ST_MC	(1L<<6)		/* Bit	6:	Multicast packet */
-#define XM_ST_UC	(1L<<5)		/* Bit	5:	Unicast packet */
-#define XM_ST_TX_UR	(1L<<4)		/* Bit	4:	FIFO Underrun occurred */
+#define XM_ST_BURST		(1L<<9)		/* Bit	9:	p. xmitted in burst md*/
+#define XM_ST_DEFER		(1L<<8)		/* Bit	8:	packet was defered */
+#define XM_ST_BC		(1L<<7)		/* Bit	7:	Broadcast packet */
+#define XM_ST_MC		(1L<<6)		/* Bit	6:	Multicast packet */
+#define XM_ST_UC		(1L<<5)		/* Bit	5:	Unicast packet */
+#define XM_ST_TX_UR		(1L<<4)		/* Bit	4:	FIFO Underrun occured */
 #define XM_ST_CS_ERR	(1L<<3)		/* Bit	3:	Carrier Sense Error */
 #define XM_ST_LAT_COL	(1L<<2)		/* Bit	2:	Late Collision Error */
 #define XM_ST_MUL_COL	(1L<<1)		/* Bit	1:	Multiple Collisions */
@@ -420,8 +421,8 @@
 
 /*	XM_RX_LO_WM	16 bit r/w	Receive Low Water Mark */
 /*	XM_RX_HI_WM	16 bit r/w	Receive High Water Mark */
-				/* Bit 15..11:	reserved */
-#define	XM_RX_WM_MSK	0x03ff	/* Bit 11.. 0:	Rx FIFO Watermark bits */
+									/* Bit 15..11:	reserved */
+#define	XM_RX_WM_MSK	0x03ff		/* Bit 11.. 0:	Rx FIFO Watermark bits */
 
 
 /*	XM_DEV_ID	32 bit ro	Device ID Register */
@@ -430,25 +431,25 @@
 
 
 /*	XM_MODE		32 bit r/w	Mode Register */
-					/* Bit 31..27:	reserved */
+									/* Bit 31..27:	reserved */
 #define XM_MD_ENA_REJ	(1L<<26)	/* Bit 26:	Enable Frame Reject */
 #define XM_MD_SPOE_E	(1L<<25)	/* Bit 25:	Send Pause on Edge */
-					/* 		extern generated */
+									/* 		extern generated */
 #define XM_MD_TX_REP	(1L<<24)	/* Bit 24:	Transmit Repeater Mode*/
 #define XM_MD_SPOFF_I	(1L<<23)	/* Bit 23:	Send Pause on FIFOfull*/
-					/*		intern generated */
+									/*		intern generated */
 #define XM_MD_LE_STW	(1L<<22)	/* Bit 22:	Rx Stat Word in Lit En*/
 #define XM_MD_TX_CONT	(1L<<21)	/* Bit 21:	Send Continuous */
 #define XM_MD_TX_PAUSE	(1L<<20)	/* Bit 20: (sc)	Send Pause Frame */
-#define XM_MD_ATS	(1L<<19)	/* Bit 19:	Append Time Stamp */
+#define XM_MD_ATS		(1L<<19)	/* Bit 19:	Append Time Stamp */
 #define XM_MD_SPOL_I	(1L<<18)	/* Bit 18:	Send Pause on Low */
-					/*		intern generated */
+									/*		intern generated */
 #define XM_MD_SPOH_I	(1L<<17)	/* Bit 17:	Send Pause on High */
-					/*		intern generated */
-#define XM_MD_CAP	(1L<<16)	/* Bit 16:	Check Address Pair */
+									/*		intern generated */
+#define XM_MD_CAP		(1L<<16)	/* Bit 16:	Check Address Pair */
 #define XM_MD_ENA_HSH	(1L<<15)	/* Bit 15:	Enable Hashing */
-#define XM_MD_CSA	(1L<<14)	/* Bit 14:	Check Station Address */
-#define XM_MD_CAA	(1L<<13)	/* Bit 13:	Check Address Array */
+#define XM_MD_CSA		(1L<<14)	/* Bit 14:	Check Station Address */
+#define XM_MD_CAA		(1L<<13)	/* Bit 13:	Check Address Array */
 #define XM_MD_RX_MCTRL	(1L<<12)	/* Bit 12:	Rx MAC Control Frames */
 #define XM_MD_RX_RUNT	(1L<<11)	/* Bit 11:	Rx Runt Frames */
 #define XM_MD_RX_IRLE	(1L<<10)	/* Bit 10:	Rx in Range Len Err F */
@@ -460,16 +461,15 @@
 #define XM_MD_DIS_BC	(1L<<4)		/* Bit	4:	Disable Rx Boradcast */
 #define XM_MD_ENA_PROM	(1L<<3)		/* Bit	3:	Enable Promiscuous */
 #define XM_MD_ENA_BE	(1L<<2)		/* Bit	2:	Enable Big Endian */
-#define XM_MD_FTF	(1L<<1)		/* Bit	1: (sc)	Flush Tx FIFO */
-#define XM_MD_FRF	(1L<<0)		/* Bit	0: (sc)	Flush Rx FIFO */
+#define XM_MD_FTF		(1L<<1)		/* Bit	1: (sc)	Flush Tx FIFO */
+#define XM_MD_FRF		(1L<<0)		/* Bit	0: (sc)	Flush Rx FIFO */
 
 #define	XM_PAUSE_MODE	(XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
 #define XM_DEF_MODE	(XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
-			 XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA |\
-			 XM_MD_CAA)
+			 XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
 
 /*	XM_STAT_CMD	16 bit r/w	Statistics Command Register */
-				/* Bit 16..6:	reserved */
+								/* Bit 16..6:	reserved */
 #define XM_SC_SNP_RXC	(1<<5)	/* Bit	5: (sc)	Snap Rx Counters */
 #define XM_SC_SNP_TXC	(1<<4)	/* Bit	4: (sc)	Snap Tx Counters */
 #define XM_SC_CP_RXC	(1<<3)	/* Bit	3: 	Copy Rx Counters Continuously */
@@ -482,28 +482,28 @@
 /*	XM_RX_EV_MSK	32 bit r/w	Rx Counter Event Mask */
 #define	XMR_MAX_SZ_OV	(1UL<<31)	/* Bit 31:	1024-MaxSize Rx Cnt Ov*/
 #define XMR_1023B_OV	(1L<<30)	/* Bit 30:	512-1023Byte Rx Cnt Ov*/
-#define XMR_511B_OV	(1L<<29)	/* Bit 29:	256-511 Byte Rx Cnt Ov*/
-#define XMR_255B_OV	(1L<<28)	/* Bit 28:	128-255 Byte Rx Cnt Ov*/
-#define XMR_127B_OV	(1L<<27)	/* Bit 27:	65-127 Byte Rx Cnt Ov */
-#define XMR_64B_OV	(1L<<26)	/* Bit 26:	64 Byte Rx Cnt Ov */
-#define XMR_UTIL_OV	(1L<<25)	/* Bit 25:	Rx Util Cnt Overflow */
-#define XMR_UTIL_UR	(1L<<24)	/* Bit 24:	Rx Util Cnt Underrun */
+#define XMR_511B_OV		(1L<<29)	/* Bit 29:	256-511 Byte Rx Cnt Ov*/
+#define XMR_255B_OV		(1L<<28)	/* Bit 28:	128-255 Byte Rx Cnt Ov*/
+#define XMR_127B_OV		(1L<<27)	/* Bit 27:	65-127 Byte Rx Cnt Ov */
+#define XMR_64B_OV		(1L<<26)	/* Bit 26:	64 Byte Rx Cnt Ov */
+#define XMR_UTIL_OV		(1L<<25)	/* Bit 25:	Rx Util Cnt Overflow */
+#define XMR_UTIL_UR		(1L<<24)	/* Bit 24:	Rx Util Cnt Underrun */
 #define XMR_CEX_ERR_OV	(1L<<23)	/* Bit 23:	CEXT Err Cnt Ov */
-					/* Bit 22:	reserved */
+									/* Bit 22:	reserved */
 #define XMR_FCS_ERR_OV	(1L<<21)	/* Bit 21:	Rx FCS Error Cnt Ov */
 #define XMR_LNG_ERR_OV	(1L<<20)	/* Bit 20:	Rx too Long Err Cnt Ov*/
-#define XMR_RUNT_OV	(1L<<19)	/* Bit 19:	Runt Event Cnt Ov */
+#define XMR_RUNT_OV		(1L<<19)	/* Bit 19:	Runt Event Cnt Ov */
 #define XMR_SHT_ERR_OV	(1L<<18)	/* Bit 18:	Rx Short Ev Err Cnt Ov*/
 #define XMR_SYM_ERR_OV	(1L<<17)	/* Bit 17:	Rx Sym Err Cnt Ov */
-					/* Bit 16:	reserved */
+									/* Bit 16:	reserved */
 #define XMR_CAR_ERR_OV	(1L<<15)	/* Bit 15:	Rx Carr Ev Err Cnt Ov */
 #define XMR_JAB_PKT_OV	(1L<<14)	/* Bit 14:	Rx Jabb Packet Cnt Ov */
-#define XMR_FIFO_OV	(1L<<13)	/* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
+#define XMR_FIFO_OV		(1L<<13)	/* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
 #define XMR_FRA_ERR_OV	(1L<<12)	/* Bit 12:	Rx Framing Err Cnt Ov */
 #define XMR_FMISS_OV	(1L<<11)	/* Bit 11:	Rx Missed Ev Cnt Ov */
-#define XMR_BURST	(1L<<10)	/* Bit 10:	Rx Burst Event Cnt Ov */
-#define XMR_INV_MOC	(1L<<9)		/* Bit	9:	Rx with inv. MAC OC Ov*/
-#define XMR_INV_MP	(1L<<8)		/* Bit	8:	Rx inv Pause Frame Ov */
+#define XMR_BURST		(1L<<10)	/* Bit 10:	Rx Burst Event Cnt Ov */
+#define XMR_INV_MOC		(1L<<9)		/* Bit	9:	Rx with inv. MAC OC Ov*/
+#define XMR_INV_MP		(1L<<8)		/* Bit	8:	Rx inv Pause Frame Ov */
 #define XMR_MCTRL_OV	(1L<<7)		/* Bit	7:	Rx MAC Ctrl-F Cnt Ov */
 #define XMR_MPAUSE_OV	(1L<<6)		/* Bit	6:	Rx Pause MAC Ctrl-F Ov*/
 #define XMR_UC_OK_OV	(1L<<5)		/* Bit	5:	Rx Unicast Frame CntOv*/
@@ -511,39 +511,39 @@
 #define XMR_BC_OK_OV	(1L<<3)		/* Bit	3:	Rx Broadcast Cnt Ov */
 #define XMR_OK_LO_OV	(1L<<2)		/* Bit	2:	Octets Rx OK Low CntOv*/
 #define XMR_OK_HI_OV	(1L<<1)		/* Bit	1:	Octets Rx OK Hi Cnt Ov*/
-#define XMR_OK_OV	(1L<<0)		/* Bit	0:	Frames Received Ok Ov */
+#define XMR_OK_OV		(1L<<0)		/* Bit	0:	Frames Received Ok Ov */
 
 #define XMR_DEF_MSK	0x00000006L	/* all bits excepting 1 and 2 */
 
 /*	XM_TX_CNT_EV	32 bit ro	Tx Counter Event Register */
 /*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
-					/* Bit 31..26:	reserved */
+									/* Bit 31..26:	reserved */
 #define XMT_MAX_SZ_OV	(1L<<25)	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
 #define XMT_1023B_OV	(1L<<24)	/* Bit 24:	512-1023Byte Tx Cnt Ov*/
-#define XMT_511B_OV	(1L<<23)	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
-#define XMT_255B_OV	(1L<<22)	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
-#define XMT_127B_OV	(1L<<21)	/* Bit 21:	65-127 Byte Tx Cnt Ov */
-#define XMT_64B_OV	(1L<<20)	/* Bit 20:	64 Byte Tx Cnt Ov */
-#define XMT_UTIL_OV	(1L<<19)	/* Bit 19:	Tx Util Cnt Overflow */
-#define XMT_UTIL_UR	(1L<<18)	/* Bit 18:	Tx Util Cnt Underrun */
+#define XMT_511B_OV		(1L<<23)	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
+#define XMT_255B_OV		(1L<<22)	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
+#define XMT_127B_OV		(1L<<21)	/* Bit 21:	65-127 Byte Tx Cnt Ov */
+#define XMT_64B_OV		(1L<<20)	/* Bit 20:	64 Byte Tx Cnt Ov */
+#define XMT_UTIL_OV		(1L<<19)	/* Bit 19:	Tx Util Cnt Overflow */
+#define XMT_UTIL_UR		(1L<<18)	/* Bit 18:	Tx Util Cnt Underrun */
 #define XMT_CS_ERR_OV	(1L<<17)	/* Bit 17:	Tx Carr Sen Err Cnt Ov*/
 #define XMT_FIFO_UR_OV	(1L<<16)	/* Bit 16:	Tx FIFO Ur Ev Cnt Ov */
 #define XMT_EX_DEF_OV	(1L<<15)	/* Bit 15:	Tx Ex Deferall Cnt Ov */
-#define XMT_DEF		(1L<<14)	/* Bit 14:	Tx Deferred Cnt Ov */
+#define XMT_DEF			(1L<<14)	/* Bit 14:	Tx Deferred Cnt Ov */
 #define XMT_LAT_COL_OV	(1L<<13)	/* Bit 13:	Tx Late Col Cnt Ov */
 #define XMT_ABO_COL_OV	(1L<<12)	/* Bit 12:	Tx abo dueto Ex Col Ov*/
 #define XMT_MUL_COL_OV	(1L<<11)	/* Bit 11:	Tx Mult Col Cnt Ov */
-#define XMT_SNG_COL	(1L<<10)	/* Bit 10:	Tx Single Col Cnt Ov */
+#define XMT_SNG_COL		(1L<<10)	/* Bit 10:	Tx Single Col Cnt Ov */
 #define XMT_MCTRL_OV	(1L<<9)		/* Bit	9:	Tx MAC Ctrl Counter Ov*/
-#define XMT_MPAUSE	(1L<<8)		/* Bit	8:	Tx Pause MAC Ctrl-F Ov*/
-#define XMT_BURST	(1L<<7)		/* Bit	7:	Tx Burst Event Cnt Ov */
-#define XMT_LONG	(1L<<6)		/* Bit	6:	Tx Long Frame Cnt Ov */
+#define XMT_MPAUSE		(1L<<8)		/* Bit	8:	Tx Pause MAC Ctrl-F Ov*/
+#define XMT_BURST		(1L<<7)		/* Bit	7:	Tx Burst Event Cnt Ov */
+#define XMT_LONG		(1L<<6)		/* Bit	6:	Tx Long Frame Cnt Ov */
 #define XMT_UC_OK_OV	(1L<<5)		/* Bit	5:	Tx Unicast Cnt Ov */
 #define XMT_MC_OK_OV	(1L<<4)		/* Bit	4:	Tx Multicast Cnt Ov */
 #define XMT_BC_OK_OV	(1L<<3)		/* Bit	3:	Tx Broadcast Cnt Ov */
 #define XMT_OK_LO_OV	(1L<<2)		/* Bit	2:	Octets Tx OK Low CntOv*/
 #define XMT_OK_HI_OV	(1L<<1)		/* Bit	1:	Octets Tx OK Hi Cnt Ov*/
-#define XMT_OK_OV	(1L<<0)		/* Bit	0:	Frames Tx Ok Ov */
+#define XMT_OK_OV		(1L<<0)		/* Bit	0:	Frames Tx Ok Ov */
 
 #define XMT_DEF_MSK	0x00000006L	/* all bits excepting 1 and 2 */
 
@@ -553,10 +553,10 @@
 #define XMR_FS_LEN	(0x3fffUL<<18)	/* Bit 31..18:	Rx Frame Length */
 #define XMR_FS_2L_VLAN	(1L<<17)	/* Bit 17:	tagged wh 2Lev VLAN ID*/
 #define XMR_FS_1L_VLAN	(1L<<16)	/* Bit 16:	tagged wh 1Lev VLAN ID*/
-#define XMR_FS_BC	(1L<<15)	/* Bit 15:	Broadcast Frame */
-#define XMR_FS_MC	(1L<<14)	/* Bit 14:	Multicast Frame */
-#define XMR_FS_UC	(1L<<13)	/* Bit 13:	Unicast Frame */
-					/* Bit 12:	reserved */
+#define XMR_FS_BC		(1L<<15)	/* Bit 15:	Broadcast Frame */
+#define XMR_FS_MC		(1L<<14)	/* Bit 14:	Multicast Frame */
+#define XMR_FS_UC		(1L<<13)	/* Bit 13:	Unicast Frame */
+									/* Bit 12:	reserved */
 #define XMR_FS_BURST	(1L<<11)	/* Bit 11:	Burst Mode */
 #define XMR_FS_CEX_ERR	(1L<<10)	/* Bit 10:	Carrier Ext. Error */
 #define XMR_FS_802_3	(1L<<9)		/* Bit	9:	802.3 Frame */
@@ -564,10 +564,10 @@
 #define XMR_FS_CAR_ERR	(1L<<7)		/* Bit	7:	Carrier Event Error */
 #define XMR_FS_LEN_ERR	(1L<<6)		/* Bit	6:	In-Range Length Error */
 #define XMR_FS_FRA_ERR	(1L<<5)		/* Bit	5:	Framing Error */
-#define XMR_FS_RUNT	(1L<<4)		/* Bit	4:	Runt Error */
+#define XMR_FS_RUNT		(1L<<4)		/* Bit	4:	Runt Error */
 #define XMR_FS_LNG_ERR	(1L<<3)		/* Bit	3:	Gaint Error */
 #define XMR_FS_FCS_ERR	(1L<<2)		/* Bit	2:	Frame Check Sequ Err */
-#define XMR_FS_ERR	(1L<<1)		/* Bit	1:	Frame Error */
+#define XMR_FS_ERR		(1L<<1)		/* Bit	1:	Frame Error */
 #define XMR_FS_MCTRL	(1L<<0)		/* Bit	0:	MAC Control Packet */
 
 /*
@@ -661,8 +661,8 @@
  */
 #define	PHY_NAT_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
 #define	PHY_NAT_STAT		0x01	/* 16 bit r/w	PHY Status Register */
-#define	PHY_NAT_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
-#define	PHY_NAT_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
+#define	PHY_NAT_ID0			0x02	/* 16 bit ro	PHY ID0 Register */
+#define	PHY_NAT_ID1			0x03	/* 16 bit ro	PHY ID1 Register */
 #define	PHY_NAT_AUNE_ADV	0x04	/* 16 bit r/w	Autonegotiation Advertisement */
 #define	PHY_NAT_AUNE_LP		0x05	/* 16 bit ro	Link Partner Ability Reg */
 #define	PHY_NAT_AUNE_EXP	0x06	/* 16 bit ro	Autonegotiation Expansion Reg */
@@ -695,16 +695,16 @@
 /*****	PHY_BCOM_CTRL	16 bit r/w	PHY Control Register *****/
 /*****	PHY_LONE_CTRL	16 bit r/w	PHY Control Register *****/
 #define	PHY_CT_RESET	(1<<15)	/* Bit 15: (sc)	clear all PHY releated regs */
-#define PHY_CT_LOOP	(1<<14)	/* Bit 14:	enable Loopback over PHY */
+#define PHY_CT_LOOP		(1<<14)	/* Bit 14:	enable Loopback over PHY */
 #define PHY_CT_SPS_LSB	(1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */
-#define PHY_CT_ANE	(1<<12)	/* Bit 12:	Autonegotiation Enabled */
+#define PHY_CT_ANE		(1<<12)	/* Bit 12:	Autonegotiation Enabled */
 #define PHY_CT_PDOWN	(1<<11)	/* Bit 11: (BC,L1) Power Down Mode */
-#define PHY_CT_ISOL	(1<<10)	/* Bit 10: (BC,L1) Isolate Mode */
+#define PHY_CT_ISOL		(1<<10)	/* Bit 10: (BC,L1) Isolate Mode */
 #define PHY_CT_RE_CFG	(1<<9)	/* Bit	9: (sc) Restart Autonegotiation */
 #define PHY_CT_DUP_MD	(1<<8)	/* Bit	8:	Duplex Mode */
 #define PHY_CT_COL_TST	(1<<7)	/* Bit	7: (BC,L1) Collsion Test enabled */
 #define PHY_CT_SPS_MSB	(1<<6)	/* Bit	6: (BC,L1) Speed select, upper bit */
-				/* Bit	5..0:	reserved */
+								/* Bit	5..0:	reserved */
 
 #define PHY_B_CT_SP1000	(1<<6)	/* Bit  6:	enable speed of 1000 MBit/s */
 #define PHY_B_CT_SP100	(1<<13)	/* Bit 13:	enable speed of  100 MBit/s */
@@ -718,10 +718,10 @@
 /*****	PHY_XMAC_STAT	16 bit r/w	PHY Status Register *****/
 /*****	PHY_BCOM_STAT	16 bit r/w	PHY Status Register *****/
 /*****	PHY_LONE_STAT	16 bit r/w	PHY Status Register *****/
-				/* Bit 15..9:	reserved */
+								/* Bit 15..9:	reserved */
 				/*	(BC/L1) 100/10 MBit/s cap bits ignored*/
 #define PHY_ST_EXT_ST	(1<<8)	/* Bit	8:	Extended Status Present */
-				/* Bit	7:	reserved */
+								/* Bit	7:	reserved */
 #define PHY_ST_PRE_SUB	(1<<6)	/* Bit	6: (BC/L1) preamble suppression */
 #define PHY_ST_AN_OVER	(1<<5)	/* Bit	5:	Autonegotiation Over */
 #define PHY_ST_REM_FLT	(1<<4)	/* Bit	4:	Remode Fault Condition Occured*/
@@ -734,9 +734,9 @@
 /*	PHY_XMAC_ID1		16 bit ro	PHY ID1 Register */
 /*	PHY_BCOM_ID1		16 bit ro	PHY ID1 Register */
 /*	PHY_LONE_ID1		16 bit ro	PHY ID1 Register */
-#define	PHY_I1_OUI	(0x3f<<10)	/* Bit 15..10:	Organiz. Unique ID */
+#define	PHY_I1_OUI		(0x3f<<10)	/* Bit 15..10:	Organiz. Unique ID */
 #define PHY_I1_MOD_NUM	(0x3f<<4)	/* Bit	9.. 4:	Model Number */
-#define PHY_I1_REV	(0x0f<<0)	/* Bit	3.. 0:	Revision Number */
+#define PHY_I1_REV		(0x0f<<0)	/* Bit	3.. 0:	Revision Number */
 
 
 /*****	PHY_XMAC_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
@@ -744,43 +744,43 @@
 #define PHY_AN_NXT_PG	(1<<15)	/* Bit 15:	Request Next Page */
 #define PHY_X_AN_ACK	(1<<14)	/* Bit 14: (ro)	Acknowledge Received */
 #define PHY_X_AN_RFB	(3<<12)	/* Bit 13..12:	Remode Fault Bits */
-				/* Bit 11.. 9:	reserved */
+								/* Bit 11.. 9:	reserved */
 #define PHY_X_AN_PAUSE	(3<<7)	/* Bit	8.. 7:	Pause Bits */
-#define PHY_X_AN_HD	(1<<6)	/* Bit	6:	Half Duplex */
-#define PHY_X_AN_FD	(1<<5)	/* Bit	5:	Full Duplex */
-				/* Bit	4.. 0:	reserved */
+#define PHY_X_AN_HD		(1<<6)	/* Bit	6:	Half Duplex */
+#define PHY_X_AN_FD		(1<<5)	/* Bit	5:	Full Duplex */
+								/* Bit	4.. 0:	reserved */
 
 /*****	PHY_BCOM_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
 /*****	PHY_BCOM_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
-/*	PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
-				/* Bit 14:	reserved */
-#define PHY_B_AN_RF	(1<<13)	/* Bit 13:	Remote Fault */
-				/* Bit 12:	reserved */
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_B_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
 #define PHY_B_AN_ASP	(1<<11)	/* Bit 11:	Asymetric Pause */
-#define PHY_B_AN_PC	(1<<10)	/* Bit 10:	Pause Capable */
-				/* Bit	9..5:	100/10 BT cap bits ingnored */
+#define PHY_B_AN_PC		(1<<10)	/* Bit 10:	Pause Capable */
+								/* Bit	9..5:	100/10 BT cap bits ingnored */
 #define PHY_B_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
 
 /*****	PHY_LONE_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
 /*****	PHY_LONE_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
-/*	PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
-				/* Bit 14:	reserved */
-#define PHY_L_AN_RF	(1<<13)	/* Bit 13:	Remote Fault */
-				/* Bit 12:	reserved */
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_L_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
 #define PHY_L_AN_ASP	(1<<11)	/* Bit 11:	Asymetric Pause */
-#define PHY_L_AN_PC	(1<<10)	/* Bit 10:	Pause Capable */
-				/* Bit	9..5:	100/10 BT cap bits ingnored */
+#define PHY_L_AN_PC		(1<<10)	/* Bit 10:	Pause Capable */
+								/* Bit	9..5:	100/10 BT cap bits ingnored */
 #define PHY_L_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
 
 /*****	PHY_NAT_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
 /*****	PHY_NAT_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
-/*	PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
-				/* Bit 14:	reserved */
-#define PHY_N_AN_RF	(1<<13)	/* Bit 13:	Remote Fault */
-				/* Bit 12:	reserved */
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_N_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
 #define PHY_N_AN_100F	(1<<11)	/* Bit 11:	100Base-T2 FD Support */
 #define PHY_N_AN_100H	(1<<10)	/* Bit 10:	100Base-T2 HD Support */
-				/* Bit	9..5:	100/10 BT cap bits ingnored */
+								/* Bit	9..5:	100/10 BT cap bits ingnored */
 #define PHY_N_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
 
 /* field type definition for PHY_x_AN_SEL */
@@ -791,22 +791,22 @@
 #define PHY_AN_LP_NP	(1<<3)	/* Bit	3:	Link Partner can Next Page */
 #define PHY_AN_LOC_NP	(1<<2)	/* Bit	2:	Local PHY can Next Page */
 #define PHY_AN_RX_PG	(1<<1)	/* Bit	1:	Page Received */
-				/* Bit	0:	reserved */
+								/* Bit	0:	reserved */
 
 /*****	PHY_BCOM_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
-				/* Bit 15..5:	reserved */
+								/* Bit 15..5:	reserved */
 #define PHY_B_AN_PDF	(1<<4)	/* Bit	4:	Parallel Detection Fault */
-/*	PHY_AN_LP_NP	(see XMAC) Bit	3:	Link Partner can Next Page */
-/*	PHY_AN_LOC_NP	(see XMAC) Bit	2:	Local PHY can Next Page */
-/*	PHY_AN_RX_PG	(see XMAC) Bit	1:	Page Received */
+/*	PHY_AN_LP_NP		(see XMAC) Bit	3:	Link Partner can Next Page */
+/*	PHY_AN_LOC_NP		(see XMAC) Bit	2:	Local PHY can Next Page */
+/*	PHY_AN_RX_PG		(see XMAC) Bit	1:	Page Received */
 #define PHY_B_AN_LP_CAP	(1<<0)	/* Bit	0:	Link Partner Autoneg Cap. */ 	
 
 /*****	PHY_LONE_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
-#define PHY_L_AN_BP	(1<<5)	/* Bit	5:	Base Page Indication */
+#define PHY_L_AN_BP		(1<<5)	/* Bit	5:	Base Page Indication */
 #define PHY_L_AN_PDF	(1<<4)	/* Bit	4:	Parallel Detection Fault */
-/*	PHY_AN_LP_NP	(see XMAC) Bit	3:	Link Partner can Next Page */
-/*	PHY_AN_LOC_NP	(see XMAC) Bit	2:	Local PHY can Next Page */
-/*	PHY_AN_RX_PG	(see XMAC) Bit	1:	Page Received */
+/*	PHY_AN_LP_NP		(see XMAC) Bit	3:	Link Partner can Next Page */
+/*	PHY_AN_LOC_NP		(see XMAC) Bit	2:	Local PHY can Next Page */
+/*	PHY_AN_RX_PG		(see XMAC) Bit	1:	Page Received */
 #define PHY_B_AN_LP_CAP	(1<<0)	/* Bit	0:	Link Partner Autoneg Cap. */ 	
 
 
@@ -816,35 +816,35 @@
 /*****	PHY_XMAC_NEPG_LP	16 bit ro	Next Page Link Partner *****/
 /*****	PHY_BCOM_NEPG_LP	16 bit ro	Next Page Link Partner *****/
 /*****	PHY_LONE_NEPG_LP	16 bit ro	Next Page Link Partner *****/
-#define PHY_NP_MORE	(1<<15)	/* Bit 15:	More, Next Pages to follow */
-#define PHY_NP_ACK1	(1<<14)	/* Bit 14: (ro)	Ack 1, for receiving a message*/
+#define PHY_NP_MORE		(1<<15)	/* Bit 15:	More, Next Pages to follow */
+#define PHY_NP_ACK1		(1<<14)	/* Bit 14: (ro)	Ack 1, for receiving a message*/
 #define PHY_NP_MSG_VAL	(1<<13)	/* Bit 13:	Message Page valid */
-#define PHY_NP_ACK2	(1<<12)	/* Bit 12:	Ack 2, comply with msg content*/
-#define PHY_NP_TOG	(1<<11)	/* Bit 11:	Toggle Bit, ensure sync */
-#define PHY_NP_MSG	0x07ff	/* Bit 10..0:	Message from/to Link Partner */
+#define PHY_NP_ACK2		(1<<12)	/* Bit 12:	Ack 2, comply with msg content*/
+#define PHY_NP_TOG		(1<<11)	/* Bit 11:	Toggle Bit, ensure sync */
+#define PHY_NP_MSG		0x07ff	/* Bit 10..0:	Message from/to Link Partner */
 
 /*
  * XMAC-Specific
  */
 /*****	PHY_XMAC_EXT_STAT	16 bit r/w	Extended Status Register *****/
-#define PHY_X_EX_FD	(1<<15)	/* Bit 15:	Device Supports Full Duplex */
-#define PHY_X_EX_HD	(1<<14)	/* Bit 14:	Device Supports Half Duplex */
-				/* Bit 13..0:	reserved */
+#define PHY_X_EX_FD		(1<<15)	/* Bit 15:	Device Supports Full Duplex */
+#define PHY_X_EX_HD		(1<<14)	/* Bit 14:	Device Supports Half Duplex */
+								/* Bit 13..0:	reserved */
 
 /*****	PHY_XMAC_RES_ABI	16 bit ro	PHY Resolved Ability *****/
-				/* Bit 15..9:	reserved */
+								/* Bit 15..9:	reserved */
 #define PHY_X_RS_PAUSE	(3<<7)	/* Bit	8..7:	selected Pause Mode */
-#define PHY_X_RS_HD	(1<<6)	/* Bit	6:	Half Duplex Mode selected */
-#define PHY_X_RS_FD	(1<<5)	/* Bit	5:	Full Duplex Mode selected */
+#define PHY_X_RS_HD		(1<<6)	/* Bit	6:	Half Duplex Mode selected */
+#define PHY_X_RS_FD		(1<<5)	/* Bit	5:	Full Duplex Mode selected */
 #define PHY_X_RS_ABLMIS (1<<4)	/* Bit	4:	duplex or pause cap mismatch */
 #define PHY_X_RS_PAUMIS (1<<3)	/* Bit	3:	pause capability missmatch */
-				/* Bit	2..0:	reserved */
+								/* Bit	2..0:	reserved */
 /*
  * Remote Fault Bits (PHY_X_AN_RFB) encoding
  */
-#define X_RFB_OK	(0<<12)	/* Bit 12..13	No errors, Link OK */
-#define X_RFB_LF	(1<<12)	/* Bit 12..13	Link Failure */
-#define X_RFB_OFF	(2<<12)	/* Bit 12..13	Offline */
+#define X_RFB_OK		(0<<12)	/* Bit 12..13	No errors, Link OK */
+#define X_RFB_LF		(1<<12)	/* Bit 12..13	Link Failure */
+#define X_RFB_OFF		(2<<12)	/* Bit 12..13	Offline */
 #define X_RFB_AN_ERR	(3<<12)	/* Bit 12..13	Autonegotiation Error */
 
 /*
@@ -866,7 +866,7 @@
 #define PHY_B_1000C_RD		(1<<10)	/* Bit	10:	Repeater/DTE */
 #define PHY_B_1000C_AFD		(1<<9)	/* Bit	9:	Advertise Full Duplex */
 #define PHY_B_1000C_AHD		(1<<8)	/* Bit	8:	Advertise Half Duplex */
-					/* Bit	7..0:	reserved */
+									/* Bit	7..0:	reserved */
 
 /***** PHY_BCOM_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
 #define PHY_B_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
@@ -875,7 +875,7 @@
 #define PHY_B_1000S_RRS		(1<<12)	/* Bit	12:	Remote Receiver Status */
 #define PHY_B_1000S_LP_FD	(1<<11)	/* Bit	11:	Link Partner can FD */
 #define PHY_B_1000S_LP_HD	(1<<10)	/* Bit	10:	Link Partner can HD */
-					/* Bit	9..8:	reserved */
+									/* Bit	9..8:	reserved */
 #define PHY_B_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
 
 /*****	PHY_BCOM_EXT_STAT	16 bit ro	Extended Status Register *****/
@@ -883,7 +883,7 @@
 #define PHY_B_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
 #define PHY_B_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
 #define PHY_B_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
-					/* Bit 11..0:	reserved */
+									/* Bit 11..0:	reserved */
 
 /*****	PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
 #define PHY_B_PEC_MAC_PHY	(1<<15)	/* Bit 15:	10BIT/GMI-Interface */
@@ -892,36 +892,36 @@
 #define PHY_B_PEC_INT_DIS	(1<<12)	/* Bit 12:	Interrupts Disabled */
 #define PHY_B_PEC_F_INT		(1<<11)	/* Bit 11:	Force Interrupt */
 #define PHY_B_PEC_BY_45		(1<<10)	/* Bit 10:	Bypass 4B5B-Decoder */
-#define PHY_B_PEC_BY_SCR	(1<<9)	/* Bit 9:	Bypass Scrambler */
-#define PHY_B_PEC_BY_MLT3	(1<<8)	/* Bit 8:	Bypass MLT3 Encoder */
-#define PHY_B_PEC_BY_RXA	(1<<7)	/* Bit 7:	Bypass Rx Alignm. */
-#define PHY_B_PEC_RES_SCR	(1<<6)	/* Bit 6:	Reset Scrambler */
-#define PHY_B_PEC_EN_LTR	(1<<5)	/* Bit 5:	Ena LED Traffic Mode */
-#define PHY_B_PEC_LED_ON	(1<<4)	/* Bit 4:	Force LED's on */
-#define PHY_B_PEC_LED_OFF	(1<<3)	/* Bit 3:	Force LED's off */
-#define PHY_B_PEC_EX_IPG	(1<<2)	/* Bit 2:	Extend Tx IPG Mode */
-#define PHY_B_PEC_3_LED		(1<<1)	/* Bit 1:	Three Link LED mode */
-#define PHY_B_PEC_HIGH_LA	(1<<0)	/* Bit 0:	GMII Fifo Elasticy */
+#define PHY_B_PEC_BY_SCR	(1<<9)	/* Bit  9:	Bypass Scrambler */
+#define PHY_B_PEC_BY_MLT3	(1<<8)	/* Bit  8:	Bypass MLT3 Encoder */
+#define PHY_B_PEC_BY_RXA	(1<<7)	/* Bit  7:	Bypass Rx Alignm. */
+#define PHY_B_PEC_RES_SCR	(1<<6)	/* Bit  6:	Reset Scrambler */
+#define PHY_B_PEC_EN_LTR	(1<<5)	/* Bit  5:	Ena LED Traffic Mode */
+#define PHY_B_PEC_LED_ON	(1<<4)	/* Bit  4:	Force LED's on */
+#define PHY_B_PEC_LED_OFF	(1<<3)	/* Bit  3:	Force LED's off */
+#define PHY_B_PEC_EX_IPG	(1<<2)	/* Bit  2:	Extend Tx IPG Mode */
+#define PHY_B_PEC_3_LED		(1<<1)	/* Bit  1:	Three Link LED mode */
+#define PHY_B_PEC_HIGH_LA	(1<<0)	/* Bit  0:	GMII Fifo Elasticy */
 
 /*****	PHY_BCOM_P_EXT_STAT	16 bit ro	PHY Extended Status Reg *****/
-					/* Bit 15..14:	reserved */
+									/* Bit 15..14:	reserved */
 #define PHY_B_PES_CROSS_STAT	(1<<13)	/* Bit 13:	MDI Crossover Status */
 #define PHY_B_PES_INT_STAT	(1<<12)	/* Bit 12:	Interrupt Status */
 #define PHY_B_PES_RRS		(1<<11)	/* Bit 11:	Remote Receiver Stat. */
 #define PHY_B_PES_LRS		(1<<10)	/* Bit 10:	Local Receiver Stat. */
-#define PHY_B_PES_LOCKED	(1<<9)	/* Bit 9:	Locked */
-#define PHY_B_PES_LS		(1<<8)	/* Bit 8:	Link Status */
-#define PHY_B_PES_RF		(1<<7)	/* Bit 7:	Remote Fault */
-#define PHY_B_PES_CE_ER		(1<<6)	/* Bit 6:	Carrier Ext Error */
-#define PHY_B_PES_BAD_SSD	(1<<5)	/* Bit 5:	Bad SSD */
-#define PHY_B_PES_BAD_ESD	(1<<4)	/* Bit 4:	Bad ESD */
-#define PHY_B_PES_RX_ER		(1<<3)	/* Bit 3:	Receive Error */
-#define PHY_B_PES_TX_ER		(1<<2)	/* Bit 2:	Transmit Error */
-#define PHY_B_PES_LOCK_ER	(1<<1)	/* Bit 1:	Lock Error */
-#define PHY_B_PES_MLT3_ER	(1<<0)	/* Bit 0:	MLT3 code Error */
+#define PHY_B_PES_LOCKED	(1<<9)	/* Bit  9:	Locked */
+#define PHY_B_PES_LS		(1<<8)	/* Bit  8:	Link Status */
+#define PHY_B_PES_RF		(1<<7)	/* Bit  7:	Remote Fault */
+#define PHY_B_PES_CE_ER		(1<<6)	/* Bit  6:	Carrier Ext Error */
+#define PHY_B_PES_BAD_SSD	(1<<5)	/* Bit  5:	Bad SSD */
+#define PHY_B_PES_BAD_ESD	(1<<4)	/* Bit  4:	Bad ESD */
+#define PHY_B_PES_RX_ER		(1<<3)	/* Bit  3:	Receive Error */
+#define PHY_B_PES_TX_ER		(1<<2)	/* Bit  2:	Transmit Error */
+#define PHY_B_PES_LOCK_ER	(1<<1)	/* Bit  1:	Lock Error */
+#define PHY_B_PES_MLT3_ER	(1<<0)	/* Bit  0:	MLT3 code Error */
 
 /*****	PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
-					/* Bit 15..8:	reserved */
+									/* Bit 15..8:	reserved */
 #define PHY_B_FC_CTR		(255<<0)/* Bit 7..0:	False Carrier Counter */
 
 /*****	PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
@@ -932,15 +932,15 @@
 #define PHY_B_AC_L_SQE		(1<<15)	/* Bit 15:	Low Squelch */
 #define PHY_B_AC_LONG_PACK	(1<<14)	/* Bit 14:	Rx Long Packets */
 #define PHY_B_AC_ER_CTRL	(3<<12)	/* Bit 13..12:	Edgerate Control */
-					/* Bit 11:	reserved */
+									/* Bit 11:	reserved */
 #define PHY_B_AC_TX_TST		(1<<10) /* Bit 10:	tx test bit, always 1 */
-					/* Bit  9.. 8:	reserved */
+									/* Bit  9.. 8:	reserved */
 #define PHY_B_AC_DIS_PRF	(1<<7)	/* Bit  7:	dis part resp filter */
-					/* Bit  6:	reserved */
+									/* Bit  6:	reserved */
 #define PHY_B_AC_DIS_PM		(1<<5)	/* Bit  5:	dis power management */
-					/* Bit  4:	reserved */
+									/* Bit  4:	reserved */
 #define PHY_B_AC_DIAG		(1<<3)	/* Bit  3:	Diagnostic Mode */
-					/* Bit  2.. 0:	reserved */
+									/* Bit  2.. 0:	reserved */
 
 /*****	PHY_BCOM_AUX_STAT	16 bit ro	Auxiliary Status Reg *****/
 #define PHY_B_AS_AN_C		(1<<15)	/* Bit 15:	AutoNeg complete */
@@ -949,37 +949,36 @@
 #define PHY_B_AS_ANAB_D		(1<<12)	/* Bit 12:	AN Ability Detect */
 #define PHY_B_AS_NPW		(1<<11)	/* Bit 11:	AN Next Page Wait */
 #define PHY_B_AS_AN_RES		(7<<8)	/* Bit 10..8:	AN HDC */
-#define PHY_B_AS_PDF		(1<<7)	/* Bit 7:	Parallel Detect. Fault*/
-#define PHY_B_AS_RF		(1<<6)	/* Bit 6:	Remote Fault */
-#define PHY_B_AS_ANP_R		(1<<5)	/* Bit 5:	AN Page Received */
-#define PHY_B_AS_LP_ANAB	(1<<4)	/* Bit 4:	LP AN Ability */
-#define PHY_B_AS_LP_NPAB	(1<<3)	/* Bit 3:	LP Next Page Ability */
-#define PHY_B_AS_LS		(1<<2)	/* Bit 2:	Link Status */
-#define PHY_B_AS_PRR		(1<<1)	/* Bit 1:	Pause Resolution-Rx */
-#define PHY_B_AS_PRT		(1<<0)	/* Bit 0:	Pause Resolution-Tx */
+#define PHY_B_AS_PDF		(1<<7)	/* Bit  7:	Parallel Detect. Fault*/
+#define PHY_B_AS_RF			(1<<6)	/* Bit  6:	Remote Fault */
+#define PHY_B_AS_ANP_R		(1<<5)	/* Bit  5:	AN Page Received */
+#define PHY_B_AS_LP_ANAB	(1<<4)	/* Bit  4:	LP AN Ability */
+#define PHY_B_AS_LP_NPAB	(1<<3)	/* Bit  3:	LP Next Page Ability */
+#define PHY_B_AS_LS			(1<<2)	/* Bit  2:	Link Status */
+#define PHY_B_AS_PRR		(1<<1)	/* Bit  1:	Pause Resolution-Rx */
+#define PHY_B_AS_PRT		(1<<0)	/* Bit  0:	Pause Resolution-Tx */
 
 /*****	PHY_BCOM_INT_STAT	16 bit ro	Interrupt Status Reg *****/
 /*****	PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
-					/* Bit 15:	reserved */
+									/* Bit 15:	reserved */
 #define PHY_B_IS_PSE		(1<<14)	/* Bit 14:	Pair Swap Error */
 #define PHY_B_IS_MDXI_SC	(1<<13)	/* Bit 13:	MDIX Status Change */
 #define PHY_B_IS_HCT		(1<<12)	/* Bit 12:	counter above 32k */
-#define PHY_B_IS_LCT		(1<<11)	/* Bit 11:	all counter below 128 */
+#define PHY_B_IS_LCT		(1<<11)	/* Bit 11:	counter above 128 */
 #define PHY_B_IS_AN_PR		(1<<10)	/* Bit 10:	Page Received */
-#define PHY_B_IS_NO_HDCL	(1<<9)	/* Bit 9:	No HCD Link */
-#define PHY_B_IS_NO_HDC		(1<<8)	/* Bit 8:	No HCD */
-#define PHY_B_IS_NEG_USHDC	(1<<7)	/* Bit 7:	Negotiated Unsup. HCD */
-#define PHY_B_IS_SCR_S_ER	(1<<6)	/* Bit 6:	Scrambler Sync Error */
-#define PHY_B_IS_RRS_CHANGE	(1<<5)	/* Bit 5:	Remote Rx Stat Change */
-#define PHY_B_IS_LRS_CHANGE	(1<<4)	/* Bit 4:	Local Rx Stat Change */
-#define PHY_B_IS_DUP_CHANGE	(1<<3)	/* Bit 3:	Duplex Mode Change */
-#define PHY_B_IS_LSP_CHANGE	(1<<2)	/* Bit 2:	Link Speed Change */
-#define PHY_B_IS_LST_CHANGE	(1<<1)	/* Bit 1:	Link Status Changed */
-#define PHY_B_IS_CRC_ER		(1<<0)	/* Bit 0:	CRC Error */
+#define PHY_B_IS_NO_HDCL	(1<<9)	/* Bit  9:	No HCD Link */
+#define PHY_B_IS_NO_HDC		(1<<8)	/* Bit  8:	No HCD */
+#define PHY_B_IS_NEG_USHDC	(1<<7)	/* Bit  7:	Negotiated Unsup. HCD */
+#define PHY_B_IS_SCR_S_ER	(1<<6)	/* Bit  6:	Scrambler Sync Error */
+#define PHY_B_IS_RRS_CHANGE	(1<<5)	/* Bit  5:	Remote Rx Stat Change */
+#define PHY_B_IS_LRS_CHANGE	(1<<4)	/* Bit  4:	Local Rx Stat Change */
+#define PHY_B_IS_DUP_CHANGE	(1<<3)	/* Bit  3:	Duplex Mode Change */
+#define PHY_B_IS_LSP_CHANGE	(1<<2)	/* Bit  2:	Link Speed Change */
+#define PHY_B_IS_LST_CHANGE	(1<<1)	/* Bit  1:	Link Status Changed */
+#define PHY_B_IS_CRC_ER		(1<<0)	/* Bit  0:	CRC Error */
 
 #define PHY_B_DEF_MSK	(~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
 
-
 /*
  * Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding
  */
@@ -1005,7 +1004,7 @@
 #define PHY_L_1000C_RD		(1<<10)	/* Bit	10:	Repeater/DTE */
 #define PHY_L_1000C_AFD		(1<<9)	/* Bit	9:	Advertise Full Duplex */
 #define PHY_L_1000C_AHD		(1<<8)	/* Bit	8:	Advertise Half Duplex */
-					/* Bit	7..0:	reserved */
+									/* Bit	7..0:	reserved */
 
 /*****	PHY_LONE_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
 #define PHY_L_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
@@ -1014,7 +1013,7 @@
 #define PHY_L_1000S_RRS		(1<<12)	/* Bit	12:	Remote Receiver Status*/
 #define PHY_L_1000S_LP_FD	(1<<11)	/* Bit	11:	Link Partner can FD */
 #define PHY_L_1000S_LP_HD	(1<<10)	/* Bit	10:	Link Partner can HD */
-					/* Bit	9..8:	reserved */
+									/* Bit	9..8:	reserved */
 #define PHY_B_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
 
 /*****	PHY_LONE_EXT_STAT	16 bit ro	Extended Status Register *****/
@@ -1022,11 +1021,11 @@
 #define PHY_L_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
 #define PHY_L_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
 #define PHY_L_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
-					/* Bit 11..0:	reserved */
+									/* Bit 11..0:	reserved */
 
 /*****	PHY_LONE_PORT_CFG	16 bit r/w	Port Configuration Reg *****/
 #define PHY_L_PC_REP_MODE	(1<<15)	/* Bit 15:	Repeater Mode */
-					/* Bit 14:	reserved */
+									/* Bit 14:	reserved */
 #define PHY_L_PC_TX_DIS		(1<<13)	/* Bit 13:	Tx output Disabled */
 #define PHY_L_PC_BY_SCR		(1<<12)	/* Bit 12:	Bypass Scrambler */
 #define PHY_L_PC_BY_45		(1<<11)	/* Bit 11:	Bypass 4B5B-Decoder */
@@ -1049,7 +1048,7 @@
 #define PHY_L_QS_COL_STAT	(1<<11)	/* Bit 11:	Collision */
 #define PHY_L_QS_L_STAT		(1<<10)	/* Bit 10:	Link is up */
 #define PHY_L_QS_DUP_MOD	(1<<9)	/* Bit 9:	Full/Half Duplex */
-#define PHY_L_QS_AN		(1<<8)	/* Bit 8:	AutoNeg is On */
+#define PHY_L_QS_AN			(1<<8)	/* Bit 8:	AutoNeg is On */
 #define PHY_L_QS_AN_C		(1<<7)	/* Bit 7:	AN is Complete */
 #define PHY_L_QS_LLE		(7<<4)	/* Bit 6:	Line Length Estim. */
 #define PHY_L_QS_PAUSE		(1<<3)	/* Bit 3:	LP advertised Pause */
@@ -1059,24 +1058,24 @@
 
 /*****	PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
 /*****	PHY_LONE_INT_STAT	16 bit ro	Interrupt Status Reg *****/
-					/* Bit 15..14:	reserved */
+									/* Bit 15..14:	reserved */
 #define PHY_L_IS_AN_F		(1<<13)	/* Bit 13:	Autoneg fault */
-					/* Bit 12:	not described */
+									/* Bit 12:	not described */
 #define PHY_L_IS_CROSS		(1<<11)	/* Bit 11:	Crossover used */
 #define PHY_L_IS_POL		(1<<10)	/* Bit 10:	Polarity correct. used*/
-#define PHY_L_IS_SS		(1<<9)	/* Bit 9:	Smart Speed Downgrade*/
+#define PHY_L_IS_SS			(1<<9)	/* Bit 9:	Smart Speed Downgrade*/
 #define PHY_L_IS_CFULL		(1<<8)	/* Bit 8:	Counter Full */
 #define PHY_L_IS_AN_C		(1<<7)	/* Bit 7:	AutoNeg Complete */
 #define PHY_L_IS_SPEED		(1<<6)	/* Bit 6:	Speed Changed */
 #define PHY_L_IS_DUP		(1<<5)	/* Bit 5:	Duplex Changed */
-#define PHY_L_IS_LS		(1<<4)	/* Bit 4:	Link Status Changed */
+#define PHY_L_IS_LS			(1<<4)	/* Bit 4:	Link Status Changed */
 #define PHY_L_IS_ISOL		(1<<3)	/* Bit 3:	Isolate Occured */
 #define PHY_L_IS_MDINT		(1<<2)	/* Bit 2: (ro)	STAT: MII Int Pending */
 #define PHY_L_IS_INTEN		(1<<1)	/* Bit 1:	ENAB: Enable IRQs */
 #define PHY_L_IS_FORCE		(1<<0)	/* Bit 0:	ENAB: Force Interrupt */
 
-#define PHY_L_DEF_MSK		(PHY_L_IS_LS | PHY_L_IS_ISOL | \
-				PHY_L_IS_INTEN)	/* int. mask */
+/* int. mask */
+#define PHY_L_DEF_MSK		(PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
 
 /*****	PHY_LONE_LED_CFG	16 bit r/w	LED Configuration Reg *****/
 #define PHY_L_LC_LEDC		(3<<14)	/* Bit 15..14:	Col/Blink/On/Off */
@@ -1091,12 +1090,12 @@
 
 /*****	PHY_LONE_PORT_CTRL	16 bit r/w	Port Control Reg *****/
 #define PHY_L_PC_TX_TCLK	(1<<15)	/* Bit 15:	Enable TX_TCLK */
-					/* Bit 14:	reserved */
+									/* Bit 14:	reserved */
 #define PHY_L_PC_ALT_NP		(1<<13)	/* Bit 14:	Alternate Next Page */
 #define PHY_L_PC_GMII_ALT	(1<<12)	/* Bit 13:	Alternate GMII driver */
-					/* Bit 11:	reserved */
+									/* Bit 11:	reserved */
 #define PHY_L_PC_TEN_CRS	(1<<10)	/* Bit 10:	Extend CRS*/
-					/* Bit 9..0:	not described */
+									/* Bit 9..0:	not described */
 
 /*****	PHY_LONE_CIM		16 bit ro	CIM Reg *****/
 #define PHY_L_CIM_ISOL		(255<<8)/* Bit 15..8:	Isolate Count */
@@ -1123,7 +1122,7 @@
 #define PHY_N_1000C_AFD		(1<<9)	/* Bit	9:	Advertise Full Duplex */
 #define PHY_N_1000C_AHD		(1<<8)	/* Bit	8:	Advertise Half Duplex */
 #define PHY_N_1000C_APC		(1<<7)	/* Bit	7:	Asymetric Pause Cap. */
-					/* Bit	6..0:	reserved */
+									/* Bit	6..0:	reserved */
 
 /***** PHY_NAT_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
 #define PHY_N_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
@@ -1133,7 +1132,7 @@
 #define PHY_N_1000S_LP_FD	(1<<11)	/* Bit	11:	Link Partner can FD */
 #define PHY_N_1000S_LP_HD	(1<<10)	/* Bit	10:	Link Partner can HD */
 #define PHY_N_1000C_LP_APC	(1<<9)	/* Bit	9:	LP Asym. Pause Cap. */
-					/* Bit	8:	reserved */
+									/* Bit	8:	reserved */
 #define PHY_N_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
 
 /*****	PHY_NAT_EXT_STAT	16 bit ro	Extended Status Register *****/
@@ -1141,7 +1140,7 @@
 #define PHY_N_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
 #define PHY_N_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
 #define PHY_N_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
-					/* Bit 11..0:	reserved */
+									/* Bit 11..0:	reserved */
 
 /* todo: those are still missing */
 /*****	PHY_NAT_EXT_CTRL1	16 bit ro	Extended Control Reg1 *****/
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skaddr.c linux/drivers/net/sk98lin/skaddr.c
--- v2.4.6/linux/drivers/net/sk98lin/skaddr.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skaddr.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skaddr.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.36 $
- * Date:	$Date: 2000/08/07 11:10:39 $
+ * Version:	$Revision: 1.40 $
+ * Date:	$Date: 2001/02/14 14:04:59 $
  * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,18 @@
  * History:
  *
  *	$Log: skaddr.c,v $
+ *	Revision 1.40  2001/02/14 14:04:59  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.39  2001/01/30 10:30:04  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.38  2001/01/25 16:26:52  rassmann
+ *	Ensured that logical address overrides are done on net's active port.
+ *	
+ *	Revision 1.37  2001/01/22 13:41:34  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
  *	Revision 1.36  2000/08/07 11:10:39  rassmann
  *	Editorial changes.
  *	
@@ -172,7 +183,7 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skaddr.c,v 1.36 2000/08/07 11:10:39 rassmann Exp $ (C) SysKonnect.";
+	"@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKADDR_C
@@ -300,7 +311,9 @@
 		break;
 
 	case SK_INIT_IO:
-		pAC->Addr.ActivePort = pAC->Rlmt.MacActive;
+		for (i = 0; i < SK_MAX_NETS; i++) {
+			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
+		}
 		
 #ifdef DEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
@@ -313,23 +326,33 @@
 
 		/* Read permanent logical MAC address from Control Register File. */
 		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
-			InAddr = (SK_U8 *)&pAC->Addr.PermanentMacAddress.a[j];
+			InAddr = (SK_U8 *)&pAC->Addr.Net[0].PermanentMacAddress.a[j];
 			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
 		}
 
-		if (!pAC->Addr.CurrentMacAddressSet) {
-			/*
-			 * Set the current logical MAC address
-			 * to the permanent one.
-			 */
-			pAC->Addr.CurrentMacAddress =
-				pAC->Addr.PermanentMacAddress;
-			pAC->Addr.CurrentMacAddressSet = SK_TRUE;
+		if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
+			/* Set the current logical MAC address to the permanent one. */
+			pAC->Addr.Net[0].CurrentMacAddress =
+				pAC->Addr.Net[0].PermanentMacAddress;
+			pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
 		}
 
 		/* Set the current logical MAC address. */
-		pAC->Addr.Port[pAC->Addr.ActivePort].Exact[0] =
-			pAC->Addr.CurrentMacAddress;
+		pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
+			pAC->Addr.Net[0].CurrentMacAddress;
+
+#if SK_MAX_NETS > 1
+		/* Set logical MAC address for net 2 to (log | 3). */
+		if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
+			pAC->Addr.Net[1].PermanentMacAddress =
+				pAC->Addr.Net[0].PermanentMacAddress;
+			pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
+			/* Set the current logical MAC address to the permanent one. */
+			pAC->Addr.Net[1].CurrentMacAddress =
+				pAC->Addr.Net[1].PermanentMacAddress;
+			pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
+		}
+#endif	/* SK_MAX_NETS > 1 */
 
 #ifdef xDEBUG
 		SK_DBG_MSG(
@@ -365,10 +388,7 @@
 		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 			pAPort = &pAC->Addr.Port[i];
 
-			/*
-			 * Read permanent port addresses from
-			 * Control Register File.
-			 */
+			/* Read permanent port addresses from Control Register File. */
 			for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
 				InAddr = (SK_U8 *)&pAPort->PermanentMacAddress.a[j];
 				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
@@ -376,9 +396,8 @@
 
 			if (!pAPort->CurrentMacAddressSet) {
 				/*
-				 * Set the current and previous physical
-				 * MAC address of this port to its permanent
-				 * MAC address.
+				 * Set the current and previous physical MAC address
+				 * of this port to its permanent MAC address.
 				 */
 				pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
 				pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
@@ -460,35 +479,35 @@
 int	SkAddrMcClear(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* I/O context */
-SK_U32	PortIdx,	/* Index of affected port */
+SK_U32	PortNumber,	/* Index of affected port */
 int		Flags)		/* permanent/non-perm, sw-only */
 {
 	int i;
 
-	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
 	if (Flags & SK_ADDR_PERMANENT) {
 
 		/* Clear RLMT multicast addresses. */
-		pAC->Addr.Port[PortIdx].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+		pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
 	}
 	else {	/* not permanent => DRV */
 
 		/* Clear InexactFilter. */
 
 		for (i = 0; i < 8; i++) {
-			pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0;
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
 		}
 
 		/* Clear DRV multicast addresses. */
 
-		pAC->Addr.Port[PortIdx].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+		pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
 	}
 
 	if (!(Flags & SK_MC_SW_ONLY)) {
-		(void)SkAddrMcUpdate(pAC, IoC, PortIdx);
+		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
 
 	return (SK_ADDR_SUCCESS);
@@ -563,7 +582,7 @@
 int	SkAddrMcAdd(
 SK_AC		*pAC,		/* adapter context */
 SK_IOC		IoC,		/* I/O context */
-SK_U32		PortIdx,	/* Port Index */
+SK_U32		PortNumber,	/* Port Number */
 SK_MAC_ADDR	*pMc,		/* multicast address to be added */
 int			Flags)		/* permanent/non-permanent */
 {
@@ -573,56 +592,57 @@
 	unsigned HashBit;
 #endif	/* !defined(SK_ADDR_CHEAT) */
 
-	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
 	if (Flags & SK_ADDR_PERMANENT) {
 #ifdef DEBUG
-		if (pAC->Addr.Port[PortIdx].NextExactMatchRlmt <
+		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
 			SK_ADDR_FIRST_MATCH_RLMT) {
-			Next0[PortIdx] |= 1;
+			Next0[PortNumber] |= 1;
 			return (SK_MC_RLMT_OVERFLOW);
 		}
 #endif	/* DEBUG */
 		
-		if (pAC->Addr.Port[PortIdx].NextExactMatchRlmt >
+		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
 			SK_ADDR_LAST_MATCH_RLMT) {
 			return (SK_MC_RLMT_OVERFLOW);
 		}
 
 		/* Set an RLMT multicast address. */
 
-		pAC->Addr.Port[PortIdx].Exact[
-			pAC->Addr.Port[PortIdx].NextExactMatchRlmt++] = *pMc;
+		pAC->Addr.Port[PortNumber].Exact[
+			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
 
 		return (SK_MC_FILTERING_EXACT);
 	}
 
+#if 0
 	/* Not PERMANENT => DRV */
-	if (PortIdx != pAC->Addr.ActivePort) {
-
+	if (PortNumber != pAC->Addr.ActivePort) {
 		/* Only RLMT is allowed to do this. */
 		return (SK_MC_ILLEGAL_PORT);
 	}
+#endif	/* 0 */
 
 #ifdef DEBUG
-	if (pAC->Addr.Port[PortIdx].NextExactMatchDrv <
+	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
 		SK_ADDR_FIRST_MATCH_DRV) {
-			Next0[PortIdx] |= 2;
+			Next0[PortNumber] |= 2;
 		return (SK_MC_RLMT_OVERFLOW);
 	}
 #endif	/* DEBUG */
 	
-	if (pAC->Addr.Port[PortIdx].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
 
 		/* Set exact match entry. */
-		pAC->Addr.Port[PortIdx].Exact[
-			pAC->Addr.Port[PortIdx].NextExactMatchDrv++] = *pMc;
+		pAC->Addr.Port[PortNumber].Exact[
+			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
 
 		/* Clear InexactFilter. */
 		for (i = 0; i < 8; i++) {
-			pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0;
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
 		}
 	}
 	else {
@@ -638,21 +658,21 @@
 		HashBit = 63 - SkCrc32McHash(&pMc->a[0]);
 
 		/* Add bit to InexactFilter. */
-		pAC->Addr.Port[PortIdx].InexactFilter.Bytes[HashBit / 8] |=
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
 			1 << (HashBit % 8);
 #else	/* SK_ADDR_CHEAT */
 		/* Set all bits in InexactFilter. */
 		for (i = 0; i < 8; i++) {
-			pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0xFF;
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
 		}
 #endif	/* SK_ADDR_CHEAT */
 	}
 
 	for (Inexact = 0, i = 0; i < 8; i++) {
-		Inexact |= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i];
+		Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
 	}
 
-	if (Inexact == 0 && pAC->Addr.Port[PortIdx].PromMode == 0) {
+	if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
 		return (SK_MC_FILTERING_EXACT);
 	}
 	else {
@@ -685,7 +705,7 @@
 int	SkAddrMcUpdate(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* I/O context */
-SK_U32	PortIdx)	/* Port Index */
+SK_U32	PortNumber)	/* Port Number */
 {
 	SK_U32			i;
 	SK_U8			Inexact;
@@ -693,7 +713,7 @@
 	SK_U16			LoMode;		/* Lower 16 bits of XMAC Mode Reg. */
 	SK_ADDR_PORT	*pAPort;
 
-	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
@@ -701,25 +721,23 @@
 		pAC,
 		SK_DBGMOD_ADDR,
 		SK_DBGCAT_CTRL,
-		("SkAddrMcUpdate on Port %u.\n", PortIdx))
+		("SkAddrMcUpdate on Port %u.\n", PortNumber))
 	
-	pAPort = &pAC->Addr.Port[PortIdx];
+	pAPort = &pAC->Addr.Port[PortNumber];
 
 #ifdef DEBUG
 		SK_DBG_MSG(
 			pAC,
 			SK_DBGMOD_ADDR,
 			SK_DBGCAT_CTRL,
-			("Next0 on Port %d: %d\n", PortIdx, Next0[PortIdx]))
+			("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
 #endif	/* DEBUG */
 
-	for (i = 0;		/* Also program the logical MAC address. */
-		i < pAPort->NextExactMatchRlmt;
-		i++) {
-
+	/* Start with 0 to also program the logical MAC address. */
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
 		/* Set exact match address i on HW. */
 		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
-		XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr);
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
 	}
 
 	/* Clear other permanent exact match addresses on HW. */
@@ -727,14 +745,14 @@
 		SkXmClrExactAddr(
 			pAC,
 			IoC,
-			PortIdx,
+			PortNumber,
 			pAPort->NextExactMatchRlmt,
 			SK_ADDR_LAST_MATCH_RLMT);
 	}
 
 	for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
 		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
-		XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr);
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
 	}
 
 	/* Clear other non-permanent exact match addresses on HW. */
@@ -742,7 +760,7 @@
 		SkXmClrExactAddr(
 			pAC,
 			IoC,
-			PortIdx,
+			PortNumber,
 			pAPort->NextExactMatchDrv,
 			SK_ADDR_LAST_MATCH_DRV);
 	}
@@ -753,54 +771,52 @@
 
 	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
 		/* Set all bits in 64-bit hash register. */
-		XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash);
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
 
 		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 	}
 	else if (Inexact != 0) {
 		/* Set 64-bit hash register to InexactFilter. */
-		XM_OUTHASH(IoC, PortIdx, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
 
 		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 	}
 	else {
 		/* Clear bit 15 in mode register. */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		LoMode &= ~XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 	}
 
 	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
-		(void)SkAddrPromiscuousChange(pAC, IoC, PortIdx, pAPort->PromMode);
+		(void)SkAddrPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
 	}
 
 	/* Set port's current MAC address. */
 	OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
-	XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr);
+	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
 
-#ifdef DEBUG
-	for (i = 0;		/* Also program the logical MAC address. */
-		i < pAPort->NextExactMatchRlmt;
-		i++) {
+#ifdef xDEBUG
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
 		SK_U8		InAddr8[6];
 		SK_U16		*InAddr;
 
-		/* Get exact match address i from port PortIdx. */
+		/* Get exact match address i from port PortNumber. */
 		InAddr = (SK_U16 *)&InAddr8[0];
-		XM_INADDR(IoC, PortIdx, XM_EXM(i), InAddr);
+		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
 		SK_DBG_MSG(
 			pAC,
-			SK_DBGMOD_RLMT,
+			SK_DBGMOD_ADDR,
 			SK_DBGCAT_CTRL,
 			("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
 				i,
-				PortIdx,
+				PortNumber,
 				InAddr8[0],
 				InAddr8[1],
 				InAddr8[2],
@@ -846,52 +862,70 @@
 int	SkAddrOverride(
 SK_AC		*pAC,		/* adapter context */
 SK_IOC		IoC,		/* I/O context */
-SK_U32		PortIdx,	/* Port Index */
+SK_U32		PortNumber,	/* Port Number */
 SK_MAC_ADDR	*pNewAddr,	/* new MAC address */
 int			Flags)		/* logical/physical MAC address */
 {
+	SK_EVPARA	Para;
+	SK_U32		NetNumber;
 	SK_U32		i;
 	SK_U16		*OutAddr;
-	SK_EVPARA	Para;
-#if 0
-	SK_MAC_ADDR	NewAddr;	/* new MAC address */
-	SK_U8		AddrBits;
-#endif	/* 0 */
 
-	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
+
+	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
-	if (pNewAddr->a[0] & SK_MC_BIT) {
+	if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
 		return (SK_ADDR_MULTICAST_ADDRESS);
 	}
 
-#if 0
-DANGEROUS!
-	if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical address. */
-		if (!pAC->Addr.Port[PortIdx].CurrentMacAddressSet) {
-			pAC->Addr.Port[PortIdx].PreviousMacAddress = *pNewAddr;
-			pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr;
-			pAC->Addr.Port[PortIdx].CurrentMacAddressSet = SK_TRUE;
-			return (SK_ADDR_SUCCESS);
-		}
+	if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
+		return (SK_ADDR_TOO_EARLY);
 	}
-	else {
-		if (!pAC->Addr.CurrentMacAddressSet) {
-			pAC->Addr.CurrentMacAddress = *pNewAddr;
-			pAC->Addr.CurrentMacAddressSet = SK_TRUE;
-			return (SK_ADDR_SUCCESS);
+
+	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */
+		/* Parameter *pNewAddr is ignored. */
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
 		}
-	}
-DANGEROUS!
-#endif	/* 0 */
 
-	if (!pAC->Addr.CurrentMacAddressSet) {
-		return (SK_ADDR_TOO_EARLY);
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+
+		pAC->Addr.Port[PortNumber].Exact[0] =
+			pAC->Addr.Net[NetNumber].CurrentMacAddress;
+
+		/* Write address to first exact match entry of active port. */
+		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
+	else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
+		/* Deactivate logical MAC address. */
+		/* Parameter *pNewAddr is ignored. */
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+		}
+
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
+			pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
+		}
 
-	if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
-		if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) {
+		/* Write address to first exact match entry of active port. */
+		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a,
+			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
 			return (SK_ADDR_DUPLICATE_ADDRESS);
 		}
 
@@ -900,10 +934,9 @@
 				return (SK_ADDR_TOO_EARLY);
 			}
 
-			if (SK_ADDR_EQUAL(
-				pNewAddr->a,
+			if (SK_ADDR_EQUAL(pNewAddr->a,
 				pAC->Addr.Port[i].CurrentMacAddress.a)) {
-				if (i == PortIdx) {
+				if (i == PortNumber) {
 					return (SK_ADDR_SUCCESS);
 				}
 				else {
@@ -912,20 +945,22 @@
 			}
 		}
 
-		pAC->Addr.Port[PortIdx].PreviousMacAddress =
-			pAC->Addr.Port[PortIdx].CurrentMacAddress;
-		pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr;
+		pAC->Addr.Port[PortNumber].PreviousMacAddress =
+			pAC->Addr.Port[PortNumber].CurrentMacAddress;
+		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
 
 		/* Change port's address. */
 		OutAddr = (SK_U16 *)pNewAddr;
-		XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr);
+		XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
 
 		/* Report address change to RLMT. */
-		Para.Para32[0] = PortIdx;
+		Para.Para32[0] = PortNumber;
+		Para.Para32[0] = -1;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
 	}
 	else {	/* Logical MAC address. */
-		if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) {
+		if (SK_ADDR_EQUAL(pNewAddr->a,
+			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
 			return (SK_ADDR_SUCCESS);
 		}
 		
@@ -934,15 +969,18 @@
 				return (SK_ADDR_TOO_EARLY);
 			}
 
-			if (SK_ADDR_EQUAL(
-				pNewAddr->a,
+			if (SK_ADDR_EQUAL(pNewAddr->a,
 				pAC->Addr.Port[i].CurrentMacAddress.a)) {
 				return (SK_ADDR_DUPLICATE_ADDRESS);
 			}
 		}
 
-		pAC->Addr.CurrentMacAddress = *pNewAddr;
-		pAC->Addr.Port[PortIdx].Exact[0] = *pNewAddr;
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+
+		pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
+		pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
 
 #ifdef DEBUG
 		SK_DBG_MSG(
@@ -950,27 +988,27 @@
 			SK_DBGMOD_ADDR,
 			SK_DBGCAT_CTRL,
 			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
-				pAC->Addr.PermanentMacAddress.a[0],
-				pAC->Addr.PermanentMacAddress.a[1],
-				pAC->Addr.PermanentMacAddress.a[2],
-				pAC->Addr.PermanentMacAddress.a[3],
-				pAC->Addr.PermanentMacAddress.a[4],
-				pAC->Addr.PermanentMacAddress.a[5]))
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
 		SK_DBG_MSG(
 			pAC,
 			SK_DBGMOD_ADDR,
 			SK_DBGCAT_CTRL,
 			("New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
-				pAC->Addr.CurrentMacAddress.a[0],
-				pAC->Addr.CurrentMacAddress.a[1],
-				pAC->Addr.CurrentMacAddress.a[2],
-				pAC->Addr.CurrentMacAddress.a[3],
-				pAC->Addr.CurrentMacAddress.a[4],
-				pAC->Addr.CurrentMacAddress.a[5]))
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
 #endif	/* DEBUG */
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortIdx);
+		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
 
 	return (SK_ADDR_SUCCESS);
@@ -998,7 +1036,7 @@
 int	SkAddrPromiscuousChange(
 SK_AC	*pAC,			/* adapter context */
 SK_IOC	IoC,			/* I/O context */
-SK_U32	PortIdx,		/* port whose promiscuous mode changes */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
 int		NewPromMode)	/* new promiscuous mode */
 {
 	int			i;
@@ -1009,31 +1047,31 @@
 	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
 	int			CurPromMode = SK_PROM_MODE_NONE;
 
-	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
 	/* Read CurPromMode from Hardware. */
-	XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 
 	if (LoMode & XM_MD_ENA_PROM) {
 		CurPromMode |= SK_PROM_MODE_LLC;
 	}
 	
 	for (Inexact = 0xFF, i = 0; i < 8; i++) {
-		Inexact &= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i];
+		Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
 	}
 	if (Inexact == 0xFF) {
-		CurPromMode |= (pAC->Addr.Port[PortIdx].PromMode & SK_PROM_MODE_ALL_MC);
+		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
 	}
 	else {
 		/* Read InexactModeBit (bit 15 in mode register). */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		
 		InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0;
 
 		/* Read 64-bit hash register from HW. */
-		XM_INHASH(IoC, PortIdx, XM_HSM, &HwInexactFilter.Bytes[0]);
+		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
 
 		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
 			HwInexact &= HwInexactFilter.Bytes[i];
@@ -1044,7 +1082,7 @@
 		}
 	}
 
-	pAC->Addr.Port[PortIdx].PromMode = NewPromMode;
+	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
 
 	if (NewPromMode == CurPromMode) {
 		return (SK_ADDR_SUCCESS);
@@ -1053,43 +1091,43 @@
 	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
 		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC. */
 		/* Set all bits in 64-bit hash register. */
-		XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash);
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
 
 		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 	}
 	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
 		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
 		for (Inexact = 0, i = 0; i < 8; i++) {
-			Inexact |= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i];
+			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
 		}
 		if (Inexact == 0) {
 			/* Clear bit 15 in mode register. */
-			XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 			LoMode &= ~XM_MD_ENA_HSH;
-			XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 		}
 		else {
 			/* Set 64-bit hash register to InexactFilter. */
 			XM_OUTHASH(
 				IoC,
-				PortIdx,
+				PortNumber,
 				XM_HSM,
-				&pAC->Addr.Port[PortIdx].InexactFilter.Bytes[0]);
+				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
 
 			/* Set bit 15 in mode register. */
-			XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 			LoMode |= XM_MD_ENA_HSH;
-			XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 		}
 	}
 
 	if ((NewPromMode & SK_PROM_MODE_LLC) &&
 		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
 		/* Set promiscuous bit in mode register. */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 
 #if 0
 		/* Receive MAC frames. */
@@ -1097,12 +1135,12 @@
 #endif	/* 0 */
 
 		LoMode |= XM_MD_ENA_PROM;
-		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 	}
 	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
 		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
 		/* Clear promiscuous bit in mode register. */
-		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 
 #if 0
 		/* Don't receive MAC frames. */
@@ -1110,7 +1148,7 @@
 #endif	/* 0 */
 		
 		LoMode &= ~XM_MD_ENA_PROM;
-		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
 	}
 	
 	return (SK_ADDR_SUCCESS);
@@ -1135,19 +1173,23 @@
 int	SkAddrSwap(
 SK_AC	*pAC,			/* adapter context */
 SK_IOC	IoC,			/* I/O context */
-SK_U32	FromPortIdx,	/* Port1 Index */
-SK_U32	ToPortIdx)		/* Port2 Index */
+SK_U32	FromPortNumber,	/* Port1 Index */
+SK_U32	ToPortNumber)		/* Port2 Index */
 {
 	int			i;
 	SK_U8		Byte;
 	SK_MAC_ADDR	MacAddr;
 	SK_U32		DWord;
 
-	if (FromPortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (FromPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (ToPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
-	if (ToPortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
@@ -1164,47 +1206,56 @@
 	 */
 
 	for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
-		MacAddr = pAC->Addr.Port[FromPortIdx].Exact[i];
-		pAC->Addr.Port[FromPortIdx].Exact[i] =
-			pAC->Addr.Port[ToPortIdx].Exact[i];
-		pAC->Addr.Port[ToPortIdx].Exact[i] = MacAddr;
+		MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
+		pAC->Addr.Port[FromPortNumber].Exact[i] =
+			pAC->Addr.Port[ToPortNumber].Exact[i];
+		pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
 	}
 
 	for (i = 0; i < 8; i++) {
-		Byte = pAC->Addr.Port[FromPortIdx].InexactFilter.Bytes[i];
-		pAC->Addr.Port[FromPortIdx].InexactFilter.Bytes[i] =
-			pAC->Addr.Port[ToPortIdx].InexactFilter.Bytes[i];
-		pAC->Addr.Port[ToPortIdx].InexactFilter.Bytes[i] = Byte;
-	}
-
-	i = pAC->Addr.Port[FromPortIdx].PromMode;
-	pAC->Addr.Port[FromPortIdx].PromMode = pAC->Addr.Port[ToPortIdx].PromMode;
-	pAC->Addr.Port[ToPortIdx].PromMode = i;
-
-	DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt;
-	pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt =
-		pAC->Addr.Port[ToPortIdx].FirstExactMatchRlmt;
-	pAC->Addr.Port[ToPortIdx].FirstExactMatchRlmt = DWord;
-
-	DWord = pAC->Addr.Port[FromPortIdx].NextExactMatchRlmt;
-	pAC->Addr.Port[FromPortIdx].NextExactMatchRlmt =
-		pAC->Addr.Port[ToPortIdx].NextExactMatchRlmt;
-	pAC->Addr.Port[ToPortIdx].NextExactMatchRlmt = DWord;
-
-	DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchDrv;
-	pAC->Addr.Port[FromPortIdx].FirstExactMatchDrv =
-		pAC->Addr.Port[ToPortIdx].FirstExactMatchDrv;
-	pAC->Addr.Port[ToPortIdx].FirstExactMatchDrv = DWord;
-
-	DWord = pAC->Addr.Port[FromPortIdx].NextExactMatchDrv;
-	pAC->Addr.Port[FromPortIdx].NextExactMatchDrv =
-		pAC->Addr.Port[ToPortIdx].NextExactMatchDrv;
-	pAC->Addr.Port[ToPortIdx].NextExactMatchDrv = DWord;
-
-	pAC->Addr.ActivePort = ToPortIdx;
+		Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
+		pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
+			pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
+		pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
+	}
+
+	i = pAC->Addr.Port[FromPortNumber].PromMode;
+	pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
+	pAC->Addr.Port[ToPortNumber].PromMode = i;
+
+	DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
+	pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
+		pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
+	pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
+
+	DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
+	pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
+		pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
+	pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
+
+	DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
+	pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
+		pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
+	pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
+
+	DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
+	pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
+		pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
+	pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
+
+	/* CAUTION: Solution works if only ports of one adapter are in use. */
+	for (i = 0; (SK_U32)i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
+		Net->NetNumber].NumPorts; i++) {
+		if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+			Port[i]->PortNumber == ToPortNumber) {
+			pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+				ActivePort = i;
+			/* 20001207 RA: Was "ToPortNumber;". */
 
-	(void)SkAddrMcUpdate(pAC, IoC, FromPortIdx);
-	(void)SkAddrMcUpdate(pAC, IoC, ToPortIdx);
+		}
+	}
+	(void)SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+	(void)SkAddrMcUpdate(pAC, IoC, ToPortNumber);
 
 	return (SK_ADDR_SUCCESS);
 }	/* SkAddrSwap */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skcsum.c linux/drivers/net/sk98lin/skcsum.c
--- v2.4.6/linux/drivers/net/sk98lin/skcsum.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skcsum.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skcsum.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.7 $
- * Date:	$Date: 2000/06/29 13:17:05 $
+ * Version:	$Revision: 1.8 $
+ * Date:	$Date: 2001/02/06 11:15:36 $
  * Purpose:	Store/verify Internet checksum in send/receive packets.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,9 @@
  * History:
  *
  *	$Log: skcsum.c,v $
+ *	Revision 1.8  2001/02/06 11:15:36  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
  *	Revision 1.7  2000/06/29 13:17:05  rassmann
  *	Corrected reception of a packet with UDP checksum == 0 (which means there
  *	is no UDP checksum).
@@ -63,7 +65,7 @@
 
 #ifndef lint
 static const char SysKonnectFileId[] = "@(#)"
-	"$Id: skcsum.c,v 1.7 2000/06/29 13:17:05 rassmann Exp $"
+	"$Id: skcsum.c,v 1.8 2001/02/06 11:15:36 rassmann Exp $"
 	" (C) SysKonnect.";
 #endif	/* !lint */
 
@@ -249,7 +251,8 @@
 void SkCsGetSendInfo(
 SK_AC				*pAc,			/* Adapter context struct. */
 void				*pIpHeader,		/* IP header. */
-SKCS_PACKET_INFO	*pPacketInfo)	/* Packet information struct. */
+SKCS_PACKET_INFO	*pPacketInfo,	/* Packet information struct. */
+int					NetNumber)		/* Net number */
 {
 	/* Internet Header Version found in IP header. */
 	unsigned InternetHeaderVersion;
@@ -291,7 +294,7 @@
 			("Tx: Unknown Internet Header Version %u.\n",
 			InternetHeaderVersion));
 		pPacketInfo->ProtocolFlags = 0;
-		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxUnableCts++;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
 		return;
 	}
 
@@ -312,13 +315,13 @@
 		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
 			("Tx: Invalid IP Header Length %u.\n", IpHeaderLength));
 		pPacketInfo->ProtocolFlags = 0;
-		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxUnableCts++;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
 		return;
 	}
 
 	/* This is an IPv4 frame with a header of valid length. */
 
-	pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxOkCts++;
+	pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++;
 
 	/* Check if we should calculate the IP header checksum. */
 
@@ -347,14 +350,14 @@
 		/* TCP/IP frame. */
 		ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP;
 		NextLevelProtoStats =
-			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP];
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
 	}
 	else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 &&
 		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
 		/* UDP/IP frame. */
 		ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP;
 		NextLevelProtoStats =
-			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP];
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
 	}
 	else {
 		/*
@@ -475,7 +478,8 @@
 SK_AC		*pAc,		/* Adapter context struct. */
 void		*pIpHeader,	/* IP header. */
 unsigned	Checksum1,	/* Hardware checksum 1. */
-unsigned	Checksum2)	/* Hardware checksum 2. */
+unsigned	Checksum2,	/* Hardware checksum 2. */
+int			NetNumber)	/* Net number */
 {
 	/* Internet Header Version found in IP header. */
 	unsigned InternetHeaderVersion;
@@ -522,7 +526,7 @@
 		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
 			("Rx: Unknown Internet Header Version %u.\n",
 			InternetHeaderVersion));
-		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxUnableCts++;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
 		return (SKCS_STATUS_UNKNOWN_IP_VERSION);
 	}
 
@@ -541,7 +545,7 @@
 	if (IpHeaderLength < 5*4) {
 		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
 			("Rx: Invalid IP Header Length %u.\n", IpHeaderLength));
-		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
 		return (SKCS_STATUS_IP_CSUM_ERROR);
 	}
 
@@ -590,7 +594,7 @@
 		SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
 
 	if (IpHeaderChecksum != 0xFFFF) {
-		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++;
+		pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
 		/* the NDIS tester wants to know the upper level protocol too */
 		if (NextLevelProtocol == SKCS_PROTO_ID_TCP) {
 			return(SKCS_STATUS_IP_CSUM_ERROR_TCP);
@@ -609,15 +613,17 @@
 	 * frame.
 	 */
 
-	if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_TCP) != 0 &&
+	if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 &&
 		NextLevelProtocol == SKCS_PROTO_ID_TCP) {
 		/* TCP/IP frame. */
-		NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP];
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
 	}
-	else if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_UDP) != 0 &&
+	else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 &&
 		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
 		/* UDP/IP frame. */
-		NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP];
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
 	}
 	else {
 		/*
@@ -755,11 +761,12 @@
 SK_AC		*pAc,				/* Adapter context struct. */
 unsigned	ReceiveFlags,		/* New receive flags. */
 unsigned	*pChecksum1Offset,	/* Offset for hardware checksum 1. */
-unsigned	*pChecksum2Offset)	/* Offset for hardware checksum 2. */
+unsigned	*pChecksum2Offset,	/* Offset for hardware checksum 2. */
+int			NetNumber)
 {
 	/* Save the receive flags. */
 
-	pAc->Csum.ReceiveFlags = ReceiveFlags;
+	pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags;
 
 	/* First checksum start offset is the IP header. */
 	*pChecksum1Offset = SKCS_MAC_HEADER_SIZE;
@@ -871,23 +878,26 @@
 SK_EVPARA	Param)	/* Event dependent parameter. */
 {
 	int ProtoIndex;
+	int	NetNumber;
 
 	switch (Event) {
 	/*
 	 * Clear protocol statistics.
 	 *
 	 * Param - Protocol index, or -1 for all protocols.
+	 *		 - Net number.
 	 */
 	case SK_CSUM_EVENT_CLEAR_PROTO_STATS:
 
-		ProtoIndex = (int) Param.Para32[0];
+		ProtoIndex = (int)Param.Para32[0];
+		NetNumber = (int)Param.Para32[1];
 		if (ProtoIndex < 0) {	/* Clear for all protocols. */
-			memset(&pAc->Csum.ProtoStats[0], 0,
-				sizeof(pAc->Csum.ProtoStats));
+			memset(&pAc->Csum.ProtoStats[NetNumber][0], 0,
+				sizeof(pAc->Csum.ProtoStats[NetNumber]));
 		}
 		else {					/* Clear for individual protocol. */
-			memset(&pAc->Csum.ProtoStats[ProtoIndex], 0,
-				sizeof(pAc->Csum.ProtoStats[ProtoIndex]));
+			memset(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0,
+				sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex]));
 		}
 		break;
 	default:
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.4.6/linux/drivers/net/sk98lin/skge.c	Wed Apr 18 14:40:05 2001
+++ linux/drivers/net/sk98lin/skge.c	Wed Jul  4 11:50:39 2001
@@ -1,20 +1,21 @@
-;/******************************************************************************
+/******************************************************************************
  *
- * Name:      	skge.c
+ * Name:    skge.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.29 $
- * Date:       	$Date: 2000/02/21 13:31:56 $
+ * Version:	$Revision: 1.29.2.6 $
+ * Date:       	$Date: 2001/05/21 07:59:29 $
  * Purpose:	The main driver source module
  *
  ******************************************************************************/
  
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
  *
  *	Driver for SysKonnect Gigabit Ethernet Server Adapters:
  *
+ *	SK-9861 (single link 1000Base-SX, VF45 Volition Plug)
+ *	SK-9862 (dual link   1000Base-SX, VF45 Volition Plug)
  *	SK-9841 (single link 1000Base-LX)
  *	SK-9842 (dual link   1000Base-LX)
  *	SK-9843 (single link 1000Base-SX)
@@ -25,6 +26,7 @@
  *	Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and 
  *	SysKonnects GEnesis Solaris driver
  *	Author: Christoph Goos (cgoos@syskonnect.de)
+ *	        Mirko Lindner (mlindner@syskonnect.de)
  *
  *	Address all question to: linux@syskonnect.de
  *
@@ -46,6 +48,27 @@
  * History:
  *
  *	$Log: skge.c,v $
+ *	Revision 1.29.2.6  2001/05/21 07:59:29  mlindner
+ *	fix: MTU init problems
+ *	
+ *	Revision 1.29.2.5  2001/05/08 11:25:08  mlindner
+ *	fix: removed VLAN error message
+ *	
+ *	Revision 1.29.2.4  2001/05/04 13:31:43  gklug
+ *	fix: do not handle eth_copy on bad fragments received.
+ *	
+ *	Revision 1.29.2.3  2001/04/23 08:06:43  mlindner
+ *	Fix: error handling
+ *	
+ *	Revision 1.29.2.2  2001/03/15 12:04:54  mlindner
+ *	Fixed memory problem
+ *	
+ *	Revision 1.29.2.1  2001/03/12 16:41:44  mlindner
+ *	add: procfs function
+ *	add: dual-net function
+ *	add: RLMT networks
+ *	add: extended PNMI features
+ *	
  *	Kernel 2.4.x specific:
  *	Revision 1.xx  2000/09/12 13:31:56  cgoos
  *	Fixed missign "dev=NULL in skge_probe.
@@ -109,7 +132,7 @@
  *	Transmit descriptor polling was not reenabled after SkGePortInit.
  *	
  *	Revision 1.16  1999/07/27 15:17:29  cgoos
- *	Added some "\n" in output strings (removed while debugging...).
+ *	Added some "\n" in output strings (removed while debuging...).
  *	
  *	Revision 1.15  1999/07/23 12:09:30  cgoos
  *	Performance optimization, rx checksumming, large frame support.
@@ -242,25 +265,17 @@
  *
  ******************************************************************************/
 
-static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect.";
-static const char SysKonnectBuildNumber[] =
-	"@(#)SK-BUILD: 3.05 (20000907) PL: 01"; 
+#include	"h/skversion.h"
 
 #include	<linux/module.h>
 #include	<linux/init.h>
+#include 	<linux/proc_fs.h>
 
 #include	"h/skdrv1st.h"
 #include	"h/skdrv2nd.h"
 
 /* defines ******************************************************************/
-
-#define BOOT_STRING	"sk98lin: Network Device Driver v3.05\n" \
-			"Copyright (C) 1999-2000 SysKonnect"
-
-#define VER_STRING	"3.05"
-
-
-/* for debugging on x86 only */
+/* for debuging on x86 only */
 /* #define BREAKPOINT() asm(" int $3"); */
 
 /* use of a transmit complete interrupt */
@@ -292,8 +307,7 @@
 // #define ROLE_A	{"Auto", }
 // #define ROLE_B	{"Auto", }
 // #define PREF_PORT	{"A", }
-// #define RLMT_MODE	{"CheckLink", }
-
+// #define RLMT_MODE	{"CheckLinkState", }
 
 #define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
 #define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
@@ -333,7 +347,18 @@
 static void	SetQueueSizes(SK_AC	*pAC);
 static int	SkGeChangeMtu(struct net_device *dev, int new_mtu);
 static void	PortReInitBmu(SK_AC*, int);
-static int	SkGeIocMib(SK_AC*, unsigned int, int);
+static int	SkGeIocMib(DEV_NET*, unsigned int, int);
+
+
+/*Extern */
+
+extern struct proc_dir_entry *pSkRootDir;
+
+//extern struct proc_dir_entry Our_Proc_Dir;
+extern int proc_read(char *buffer, char **buffer_location,
+	off_t offset, int buffer_length, int *eof, void *data);
+
+
 #ifdef DEBUG
 static void	DumpMsg(struct sk_buff*, char*);
 static void	DumpData(char*, int);
@@ -343,13 +368,27 @@
 
 /* global variables *********************************************************/
 static const char *BootString = BOOT_STRING;
-static struct net_device *root_dev;
+static struct net_device *root_dev = NULL;
 static int probed __initdata = 0;
+struct inode_operations SkInodeOps;
+//static struct file_operations SkFileOps;  /* with open/relase */
 
 /* local variables **********************************************************/
 static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
 static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
 
+
+
+void proc_fill_inode(struct inode *inode, int fill)
+{
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+}
+
+
+
 /*****************************************************************************
  *
  * 	skge_probe - find all SK-98xx adapters
@@ -365,12 +404,14 @@
  */
 static int __init skge_probe (void)
 {
-	int boards_found = 0;
-	int		version_disp = 0;
+	int 		boards_found = 0;
+	int			version_disp = 0;
 	SK_AC		*pAC;
-	struct pci_dev	*pdev = NULL;
-	unsigned long	base_address;
+	DEV_NET		*pNet = NULL;
+	struct 		pci_dev	*pdev = NULL;
+	unsigned long		base_address;
 	struct net_device *dev = NULL;
+	struct proc_dir_entry	*pProcFile;
 
 	if (probed)
 		return -ENODEV;
@@ -388,27 +429,46 @@
 	if (!pci_present())		/* is PCI support present? */
 		return -ENODEV;
 
+        pSkRootDir = create_proc_entry("sk98lin",
+                S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net); 
+
+	pSkRootDir->owner = THIS_MODULE;
+
 	while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT,
 				      PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) {
-		if (pci_enable_device(pdev))
-			continue;
 
 		dev = NULL;
-		dev = init_etherdev(dev, sizeof(SK_AC));
+		pNet = NULL;
+
+		if (pci_enable_device(pdev))
+			continue;
 
-		if (dev == NULL) {
+		if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) {
 			printk(KERN_ERR "Unable to allocate etherdev "
 			       "structure!\n");
 			break;
 		}
 
-		pAC = dev->priv;
+		pNet = dev->priv;
+		pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL);
+		if (pNet->pAC == NULL){
+			kfree(dev->priv);
+			printk(KERN_ERR "Unable to allocate adapter "
+			       "structure!\n");
+			break;
+		}
+
+		memset(pNet->pAC, 0, sizeof(SK_AC));
+		pAC = pNet->pAC;
 		pAC->PciDev = *pdev;
 		pAC->PciDevId = pdev->device;
-		pAC->dev = dev;
+		pAC->dev[0] = dev;
+		pAC->dev[1] = dev;
 		sprintf(pAC->Name, "SysKonnect SK-98xx");
 		pAC->CheckQueue = SK_FALSE;
-
+		
+		pNet->Mtu = 1500;
+		pNet->Up = 0;
 		dev->irq = pdev->irq;
 
 		dev->open =		&SkGeOpen;
@@ -419,14 +479,20 @@
 		dev->set_mac_address =	&SkGeSetMacAddr;
 		dev->do_ioctl =		&SkGeIoctl;
 		dev->change_mtu =	&SkGeChangeMtu;
-		
+
+		pProcFile = create_proc_entry(dev->name, 
+			S_IFREG | 0444, pSkRootDir);
+		pProcFile->read_proc = proc_read;
+		pProcFile->write_proc = NULL;
+		pProcFile->nlink = 1;
+		pProcFile->size = sizeof(dev->name+1);
+		pProcFile->data = (void*)pProcFile;
+
 		/*
 		 * Dummy value.
 		 */
 		dev->base_addr = 42;
-
 		pci_set_master(pdev);
-
 		base_address = pci_resource_start (pdev, 0);
 
 #ifdef SK_BIG_ENDIAN
@@ -446,24 +512,28 @@
 		 * Remap the regs into kernel space.
 		 */
 
-
 		pAC->IoBase = (char*)ioremap(base_address, 0x4000);
 		if (!pAC->IoBase){
 			printk(KERN_ERR "%s:  Unable to map I/O register, "
 			       "SK 98xx No. %i will be disabled.\n",
 			       dev->name, boards_found);
+			kfree(dev);
 			break;
 		}
 		pAC->Index = boards_found;
 
 		if (SkGeBoardInit(dev, pAC)) {
 			FreeResources(dev);
+			kfree(dev);
 			continue;
 		}
 
-                memcpy((caddr_t) &dev->dev_addr,
-			(caddr_t) &pAC->Addr.CurrentMacAddress, 6);
- 
+		memcpy((caddr_t) &dev->dev_addr,
+			(caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6);
+
+		pNet->PortNr = 0;
+		pNet->NetNr = 0;
+
 		boards_found++;
 
 		/*
@@ -499,10 +569,12 @@
 static void FreeResources(struct net_device *dev)
 {
 SK_U32 AllocFlag;
-SK_AC	*pAC;
+DEV_NET		*pNet;
+SK_AC		*pAC;
 
 	if (dev->priv) {
-		pAC = (SK_AC*) dev->priv;
+		pNet = (DEV_NET*) dev->priv;
+		pAC = pNet->pAC;
 		AllocFlag = pAC->AllocFlag;
 		if (AllocFlag & SK_ALLOC_IRQ) {
 			free_irq(dev->irq, dev);
@@ -517,13 +589,6 @@
 	
 } /* FreeResources */
 
-
-static struct pci_device_id skge_pci_tbl[] __initdata = {
-	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, PCI_ANY_ID, PCI_ANY_ID, },
-	{ }			/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
-
 MODULE_AUTHOR("Christoph Goos <cgoos@syskonnect.de>");
 MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
 MODULE_PARM(AutoNeg_A,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
@@ -602,8 +667,8 @@
 #endif
 
 
-static int debug; /* not used */
-static int options[SK_MAX_CARD_PARAM]; /* not used */
+static int debug = 0; /* not used */
+static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */
 
 
 /*****************************************************************************
@@ -620,7 +685,6 @@
 static int __init skge_init_module(void)
 {
 	int cards;
-
 	root_dev = NULL;
 	
 	/* just to avoid warnings ... */
@@ -647,21 +711,28 @@
  */
 static void __exit skge_cleanup_module(void)
 {
-SK_AC	*pAC;
+DEV_NET		*pNet;
+SK_AC		*pAC;
 struct net_device *next;
 unsigned long Flags;
 SK_EVPARA EvPara;
 
 	while (root_dev) {
-		pAC = (SK_AC*)root_dev->priv;
+		pNet = (DEV_NET*) root_dev->priv;
+		pAC = pNet->pAC;
 		next = pAC->Next;
 
 		netif_stop_queue(root_dev);
 		SkGeYellowLED(pAC, pAC->IoBase, 0);
-		
+
 		if(pAC->BoardLevel == 2) {
 			/* board is still alive */
 			spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+			EvPara.Para32[0] = 0;
+			EvPara.Para32[1] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+			EvPara.Para32[0] = 1;
+			EvPara.Para32[1] = -1;
 			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
 			SkEventDispatcher(pAC, pAC->IoBase);
 			/* disable interrupts */
@@ -671,15 +742,20 @@
 			pAC->BoardLevel = 0;
 			/* We do NOT check here, if IRQ was pending, of course*/
 		}
-	
+
 		if(pAC->BoardLevel == 1) {
 			/* board is still alive */
 			SkGeDeInit(pAC, pAC->IoBase); 
 			pAC->BoardLevel = 0;
 		}
-		
+
+		if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){
+			unregister_netdev(pAC->dev[1]);
+			kfree(pAC->dev[1]);
+		}
+
 		FreeResources(root_dev);
-		
+
 		root_dev->get_stats = NULL;
 		/* 
 		 * otherwise unregister_netdev calls get_stats with
@@ -687,9 +763,13 @@
 		 */
 		unregister_netdev(root_dev);
 		kfree(root_dev);
-
+		kfree(pAC);
 		root_dev = next;
 	}
+
+	/* clear proc-dir */
+	remove_proc_entry(pSkRootDir->name, proc_net);
+
 } /* skge_cleanup_module */
 
 module_init(skge_init_module);
@@ -757,8 +837,6 @@
 
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
 
-	GetConfiguration(pAC);
-
 	/* level 1 init common modules here (HW init) */
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
 	if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
@@ -773,6 +851,12 @@
 	SkRlmtInit( pAC, pAC->IoBase, 1);
 	SkTimerInit(pAC, pAC->IoBase, 1);
 
+	GetConfiguration(pAC);
+	if (pAC->RlmtNets == 2) {
+		pAC->GIni.GIPortUsage = SK_MUL_LINK;
+	}
+
+
 	pAC->BoardLevel = 1;
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
 
@@ -801,7 +885,7 @@
 
 	SkCsSetReceiveFlags(pAC,
 		SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP,
-		&pAC->CsOfs1, &pAC->CsOfs2);
+		&pAC->CsOfs1, &pAC->CsOfs2, 0);
 	pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1;
 
 	BoardInitMem(pAC);
@@ -814,11 +898,13 @@
 
 	/* Print configuration settings */
 	printk("      PrefPort:%c  RlmtMode:%s\n",
-		'A' + pAC->Rlmt.PrefPort,
-		(pAC->RlmtMode==0)  ? "ChkLink" :
-		((pAC->RlmtMode==1) ? "ChkLink" :
-		((pAC->RlmtMode==3) ? "ChkOth" :
-		((pAC->RlmtMode==7) ? "ChkSeg" : "Error"))));
+		'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber,
+		(pAC->RlmtMode==0)  ? "Check Link State" :
+		((pAC->RlmtMode==1) ? "Check Link State" : 
+		((pAC->RlmtMode==3) ? "Check Local Port" : 
+		((pAC->RlmtMode==7) ? "Check Segmentation" : 
+		((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
+
 
 	SkGeYellowLED(pAC, pAC->IoBase, 1);
 
@@ -1103,10 +1189,13 @@
 static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 struct net_device *dev = (struct net_device *)dev_id;
+
+DEV_NET		*pNet;
 SK_AC		*pAC;
 SK_U32		IntSrc;		/* interrupts source register contents */	
 
-	pAC = (SK_AC*) dev->priv;
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
 	
 	/*
 	 * Check and process if its our interrupt
@@ -1129,21 +1218,21 @@
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF RX1 IRQ\n"));
 			ReceiveIrq(pAC, &pAC->RxPort[0]);
-			SK_PNMI_CNT_RX_INTR(pAC);
+			SK_PNMI_CNT_RX_INTR(pAC,0);
 		}
 		if (IntSrc & IRQ_EOF_RX2) {
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF RX2 IRQ\n"));
 			ReceiveIrq(pAC, &pAC->RxPort[1]);
-			SK_PNMI_CNT_RX_INTR(pAC);
+			SK_PNMI_CNT_RX_INTR(pAC,1);
 		}
 #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
 		if (IntSrc & IRQ_EOF_AS_TX1) {
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF AS TX1 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC);
+			SK_PNMI_CNT_TX_INTR(pAC,0);
 			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
 			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
 			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
@@ -1152,7 +1241,7 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF AS TX2 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC);
+			SK_PNMI_CNT_TX_INTR(pAC,1);
 			spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
 			FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
 			spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
@@ -1162,7 +1251,7 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF SY TX1 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC);
+			SK_PNMI_CNT_TX_INTR(pAC,0);
 			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
 			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
 			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
@@ -1172,7 +1261,7 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF SY TX2 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC);
+			SK_PNMI_CNT_TX_INTR(pAC,1);
 			spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
 			FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
 			spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
@@ -1210,8 +1299,12 @@
 	 * came in after handling the ring (OUTs may be delayed
 	 * in hardware buffers, but are through after IN)
 	 */
-	ReceiveIrq(pAC, &pAC->RxPort[pAC->ActivePort]);
-//	ReceiveIrq(pAC, &pAC->RxPort[1]);
+	// ReceiveIrq(pAC, &pAC->RxPort[pAC->ActivePort]);
+	ReceiveIrq(pAC, &pAC->RxPort[0]);
+	ReceiveIrq(pAC, &pAC->RxPort[1]);
+	
+
+
 
 #if 0
 // #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
@@ -1257,10 +1350,12 @@
 static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 struct net_device *dev = (struct net_device *)dev_id;
+DEV_NET		*pNet;
 SK_AC		*pAC;
 SK_U32		IntSrc;		/* interrupts source register contents */	
 
-	pAC = (SK_AC*) dev->priv;
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
 	
 	/*
 	 * Check and process if its our interrupt
@@ -1283,14 +1378,14 @@
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF RX1 IRQ\n"));
 			ReceiveIrq(pAC, &pAC->RxPort[0]);
-			SK_PNMI_CNT_RX_INTR(pAC);
+			SK_PNMI_CNT_RX_INTR(pAC,0);
 		}
 #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
 		if (IntSrc & IRQ_EOF_AS_TX1) {
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF AS TX1 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC);
+			SK_PNMI_CNT_TX_INTR(pAC,0);
 			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
 			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
 			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
@@ -1300,7 +1395,7 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF SY TX1 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC);
+			SK_PNMI_CNT_TX_INTR(pAC,1);
 			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
 			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
 			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
@@ -1376,12 +1471,14 @@
 static int SkGeOpen(
 struct net_device	*dev)
 {
-SK_AC		*pAC;		/* pointer to adapter context struct */
+DEV_NET			*pNet;
+SK_AC			*pAC;
 unsigned int	Flags;		/* for spin lock */
 int		i;
-SK_EVPARA	EvPara;		/* an event parameter union */
+SK_EVPARA		EvPara;		/* an event parameter union */
 
-	pAC = (SK_AC*) dev->priv;
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
 	
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC));
@@ -1389,7 +1486,7 @@
 	if (pAC->BoardLevel == 0) {
 		/* level 1 init common modules here */
 		if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
-			printk("%s: HWInit(1) failed\n", pAC->dev->name);
+			printk("%s: HWInit(1) failed\n", pAC->dev[pNet->PortNr]->name);
 			return (-1);
 		}
 		SkI2cInit	(pAC, pAC->IoBase, 1);
@@ -1400,26 +1497,27 @@
 		SkTimerInit	(pAC, pAC->IoBase, 1);
 		pAC->BoardLevel = 1;
 	}
-		
-	/* level 2 init modules here */
-	SkGeInit	(pAC, pAC->IoBase, 2);
-	SkI2cInit	(pAC, pAC->IoBase, 2);
-	SkEventInit	(pAC, pAC->IoBase, 2);
-	SkPnmiInit	(pAC, pAC->IoBase, 2);
-	SkAddrInit	(pAC, pAC->IoBase, 2);
-	SkRlmtInit	(pAC, pAC->IoBase, 2);
-	SkTimerInit	(pAC, pAC->IoBase, 2);
-	pAC->BoardLevel = 2;
-	
+
+	if (pAC->BoardLevel != 2) {
+		/* level 2 init modules here */
+		SkGeInit	(pAC, pAC->IoBase, 2);
+		SkI2cInit	(pAC, pAC->IoBase, 2);
+		SkEventInit	(pAC, pAC->IoBase, 2);
+		SkPnmiInit	(pAC, pAC->IoBase, 2);
+		SkAddrInit	(pAC, pAC->IoBase, 2);
+		SkRlmtInit	(pAC, pAC->IoBase, 2);
+		SkTimerInit	(pAC, pAC->IoBase, 2);
+		pAC->BoardLevel = 2;
+	}
 	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-		// Enable transmit descriptor polling.
+		/* Enable transmit descriptor polling. */
 		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
 		FillRxRing(pAC, &pAC->RxPort[i]);
 	}
 	SkGeYellowLED(pAC, pAC->IoBase, 1);
 
 #ifdef USE_INT_MOD
-// moderate only TX complete interrupts (these are not time critical)
+/* moderate only TX complete interrupts (these are not time critical) */
 #define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2)
 	{
 		unsigned long ModBase;
@@ -1435,17 +1533,29 @@
 	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
 
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
-	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
-	if (pAC->RlmtMode != 0) {
+
+	if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) {
+		EvPara.Para32[0] = pAC->RlmtNets;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+			EvPara);
 		EvPara.Para32[0] = pAC->RlmtMode;
+		EvPara.Para32[1] = 0;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE,
 			EvPara);
 	}
+
+	EvPara.Para32[0] = pNet->NetNr;
+	EvPara.Para32[1] = -1;
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
 	SkEventDispatcher(pAC, pAC->IoBase);
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
-	
+
+	pAC->MaxPorts++;
+	pNet->Up = 1;
+
 	MOD_INC_USE_COUNT;
-	
+
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeOpen suceeded\n"));
 
@@ -1467,48 +1577,84 @@
 static int SkGeClose(
 struct net_device	*dev)
 {
+DEV_NET		*pNet;
 SK_AC		*pAC;
+
 unsigned int	Flags;		/* for spin lock */
-int		i;
-SK_EVPARA	EvPara;
+int				i;
+int				PortIdx;
+SK_EVPARA		EvPara;
 
 	netif_stop_queue(dev);
 
-	pAC = (SK_AC*) dev->priv;
-	
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
+	if (pAC->RlmtNets == 1)
+		PortIdx = pAC->ActivePort;
+	else
+		PortIdx = pNet->NetNr;
+
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeClose: pAC=0x%lX ", (unsigned long)pAC));
 
 	/* 
 	 * Clear multicast table, promiscuous mode ....
 	 */
-	SkAddrMcClear(pAC, pAC->IoBase, pAC->ActivePort, 0);
-	SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+	 
+	SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+	SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
 		SK_PROM_MODE_NONE);
 
+	if (pAC->MaxPorts == 1) {
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		EvPara.Para32[0] = pNet->NetNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		/* stop the hardware */
+		SkGeDeInit(pAC, pAC->IoBase);
+		pAC->BoardLevel = 0;
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	} else {
 
-	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
-	/* disable interrupts */
-	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
-	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
-	SkEventDispatcher(pAC, pAC->IoBase);
-	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
-	/* stop the hardware */
-	SkGeDeInit(pAC, pAC->IoBase);
-	pAC->BoardLevel = 0;
-	
-	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
-
-	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		EvPara.Para32[0] = pNet->NetNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		
+		/* Stop port */
+		spin_lock_irqsave(&pAC->TxPort[pNet->PortNr]
+			[TX_PRIO_LOW].TxDesRingLock, Flags);
+		SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr, 
+			SK_STOP_ALL, SK_HARD_RST);
+		spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr]
+			[TX_PRIO_LOW].TxDesRingLock, Flags);
+	}
+	if (pAC->RlmtNets == 1) {
 		/* clear all descriptor rings */
-		ReceiveIrq(pAC, &pAC->RxPort[i]);
-		ClearRxRing(pAC, &pAC->RxPort[i]);
-		ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			ReceiveIrq(pAC, &pAC->RxPort[i]);
+			ClearRxRing(pAC, &pAC->RxPort[i]);
+			ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+		}
+	} else {
+		/* clear port descriptor rings */
+		ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr]);
+		ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]);
+		ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]);
 	}
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeClose: done "));
 
+	pAC->MaxPorts--;
+	pNet->Up = 0;
 	MOD_DEC_USE_COUNT;
 	
 	return (0);
@@ -1531,12 +1677,17 @@
  */
 static int SkGeXmit(struct sk_buff *skb, struct net_device *dev)
 {
+DEV_NET		*pNet;
 SK_AC		*pAC;
-int		Rc;	/* return code of XmitFrame */
+int			Rc;	/* return code of XmitFrame */
 	
-	pAC = (SK_AC*) dev->priv;
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
 
-	Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb);
+	if (pAC->RlmtNets == 2)
+		Rc = XmitFrame(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW], skb);
+	else
+		Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb);
 
 	/* Transmitter out of resources? */
 	if (Rc <= 0)
@@ -1551,7 +1702,7 @@
 	dev->trans_start = jiffies;
 	return (0);
 } /* SkGeXmit */
-	
+
 
 /*****************************************************************************
  *
@@ -1570,10 +1721,10 @@
  *	if necessary.
  *
  * Returns:
- *	> 0 - on succes: the number of bytes in the message
- *	= 0 - on resource shortage: this frame sent or dropped, now
+ *  > 0 - on succes: the number of bytes in the message
+ *  = 0 - on resource shortage: this frame sent or dropped, now
  *        the ring is full ( -> set tbusy)
- *	< 0 - on failure: other problems ( -> return failure to upper layers)
+ *  < 0 - on failure: other problems ( -> return failure to upper layers)
  */
 static int XmitFrame(
 SK_AC 		*pAC,		/* pointer to adapter context */
@@ -1595,7 +1746,7 @@
 		FreeTxDescriptors(pAC, pTxPort);
 		if (pTxPort->TxdRingFree == 0) {
 			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
-			SK_PNMI_CNT_NO_TX_BUF(pAC);
+			SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_TX_PROGRESS,
 				("XmitFrame failed\n"));
@@ -1699,13 +1850,13 @@
 			 * freed ( -> ring completely free now).
 			 */
 			pTxPort->pTxdRingTail = pTxd;
-			netif_start_queue(pAC->dev);
+			netif_start_queue(pAC->dev[pTxPort->PortIndex]);
 			return;
 		}
 		if (Control & TX_CTRL_OWN_BMU) {
 			pTxPort->pTxdRingTail = pTxd;
 			if (pTxPort->TxdRingFree > 0) {
-				netif_start_queue(pAC->dev);
+				netif_start_queue(pAC->dev[pTxPort->PortIndex]);
 			}
 			return;
 		}
@@ -1784,8 +1935,8 @@
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 			SK_DBGCAT_DRV_ENTRY,
 			("%s: Allocation of rx buffer failed !\n",
-			pAC->dev->name));
-		SK_PNMI_CNT_NO_RX_BUF(pAC);
+			pAC->dev[pRxPort->PortIndex]->name));
+		SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex);
 		return(SK_FALSE);
 	}
 	skb_reserve(pMsgBlock, 2); /* to align IP frames */
@@ -1877,64 +2028,110 @@
 int		Result;
 SK_U64		PhysAddr;
 
-
 rx_start:	
 	/* do forever; exit if RX_CTRL_OWN_BMU found */
-	while (pRxPort->RxdRingFree < pAC->RxDescrPerRing) {
-		pRxd = pRxPort->pRxdRingHead;
-		
+	for ( pRxd = pRxPort->pRxdRingHead ;
+		  pRxPort->RxdRingFree < pAC->RxDescrPerRing ;
+		  pRxd = pRxd->pNextRxd,
+		  pRxPort->pRxdRingHead = pRxd,
+		  pRxPort->RxdRingFree ++) {
+
+		/*
+		 * For a better understanding of this loop 
+		 * Go through every descriptor beginning at the head 
+		 * Please note: the ring might be completely received so the OWN bit
+		 * set is not a good crirteria to leave that loop.
+		 * Therefore the RingFree counter is used.
+		 * On entry of this loop pRxd is a pointer to the Rxd that needs
+		 * to be checked next.
+		 */
+
 		Control = pRxd->RBControl;
-		
+	
 		/* check if this descriptor is ready */
 		if ((Control & RX_CTRL_OWN_BMU) != 0) {
 			/* this descriptor is not yet ready */
+			/* This is the usual end of the loop */
+			/* We don't need to start the ring again */
 			FillRxRing(pAC, pRxPort);
 			return;
 		}
-		
+
 		/* get length of frame and check it */
 		FrameLength = Control & RX_CTRL_LEN_MASK;
-		if (FrameLength > pAC->RxBufSize)
+		if (FrameLength > pAC->RxBufSize) {
 			goto rx_failed;
+		}
 
 		/* check for STF and EOF */
 		if ((Control & (RX_CTRL_STF | RX_CTRL_EOF)) !=
-			(RX_CTRL_STF | RX_CTRL_EOF))
+			(RX_CTRL_STF | RX_CTRL_EOF)) {
 			goto rx_failed;
+		}
 		
 		/* here we have a complete frame in the ring */
 		pMsg = pRxd->pMBuf;
+
+		FrameStat = pRxd->FrameStat;
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+			("Received frame of length %d on port %d\n",
+			FrameLength, PortIndex));
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+			("Number of free rx descriptors: %d\n",
+			pRxPort->RxdRingFree));
+		/*DumpMsg(pMsg, "Rx");	*/	
 		
+		if ((Control & RX_CTRL_STAT_VALID) != RX_CTRL_STAT_VALID ||
+			(FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) {
+			/* there is a receive error in this frame */
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS,
+				("skge: Error in received frame, dropped!\n"
+				"Control: %x\nRxStat: %x\n",
+				Control, FrameStat));
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+			pci_dma_sync_single(&pAC->PciDev,
+						(dma_addr_t) PhysAddr,
+						FrameLength,
+						PCI_DMA_FROMDEVICE);
+			ReQueueRxBuffer(pAC, pRxPort, pMsg,
+				pRxd->VDataHigh, pRxd->VDataLow);
+
+			continue;
+		}
+
 		/*
 		 * if short frame then copy data to reduce memory waste
 		 */
-		pNewMsg = NULL;
-		if (FrameLength < SK_COPY_THRESHOLD) {
-			pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC);
-			if (pNewMsg != NULL) {
-				PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
-				PhysAddr |= (SK_U64) pRxd->VDataLow;
-
-				/* use new skb and copy data */
-				skb_reserve(pNewMsg, 2);
-				skb_put(pNewMsg, FrameLength);
-				pci_dma_sync_single(&pAC->PciDev,
-						    (dma_addr_t) PhysAddr,
-						    FrameLength,
-						    PCI_DMA_FROMDEVICE);
-				eth_copy_and_sum(pNewMsg, pMsg->data,
-					FrameLength, 0);
-				ReQueueRxBuffer(pAC, pRxPort, pMsg,
-					pRxd->VDataHigh, pRxd->VDataLow);
-				pMsg = pNewMsg;
-			}
+		if ((FrameLength < SK_COPY_THRESHOLD) &&
+			((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) {
+			/*
+			 * Short frame detected and allocation successfull
+			 */
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+			/* use new skb and copy data */
+			skb_reserve(pNewMsg, 2);
+			skb_put(pNewMsg, FrameLength);
+			pci_dma_sync_single(&pAC->PciDev,
+						(dma_addr_t) PhysAddr,
+						FrameLength,
+						PCI_DMA_FROMDEVICE);
+			eth_copy_and_sum(pNewMsg, pMsg->data,
+				FrameLength, 0);
+			ReQueueRxBuffer(pAC, pRxPort, pMsg,
+				pRxd->VDataHigh, pRxd->VDataLow);
+			pMsg = pNewMsg;
+
 		}
+		else {
+			/*
+			 * if large frame, or SKB allocation failed, pass
+			 * the SKB directly to the networking
+			 */
 
-		/*
-		 * if large frame, or SKB allocation failed, pass
-		 * the SKB directly to the networking
-		 */
-		if (pNewMsg == NULL) {
 			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
 
@@ -1954,7 +2151,7 @@
 				if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) {
 					Result = SkCsGetReceiveInfo(pAC,
 						&pMsg->data[14], 
-						Csum1, Csum2);
+						Csum1, Csum2, pRxPort->PortIndex);
 					if (Result == 
 						SKCS_STATUS_IP_FRAGMENT ||
 						Result ==
@@ -1970,123 +2167,85 @@
 			} /* IP frame */
 		} /* frame > SK_COPY_TRESHOLD */
 		
-		FrameStat = pRxd->FrameStat;
-                if ((FrameStat & XMR_FS_LNG_ERR) != 0) {
-                        /* jumbo frame, count to correct statistic */
-                        SK_PNMI_CNT_RX_LONGFRAMES(pAC, pRxPort->PortIndex);
-                }
-		pRxd = pRxd->pNextRxd;
-		pRxPort->pRxdRingHead = pRxd;
-		pRxPort->RxdRingFree ++;
-		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS,
-			("Received frame of length %d on port %d\n",
-			FrameLength, PortIndex));
-		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS,
-			("Number of free rx descriptors: %d\n",
-			pRxPort->RxdRingFree));
-		
-		if ((Control & RX_CTRL_STAT_VALID) == RX_CTRL_STAT_VALID &&
-			(FrameStat & XMR_FS_ANY_ERR) == 0) {
-			// was the following, changed to allow VLAN support
-			// (XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN)
-			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
-				SK_DBGCAT_DRV_RX_PROGRESS,("V"));
-			ForRlmt = SK_RLMT_RX_PROTOCOL;
-			IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
-			SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
-				IsBc, &Offset, &NumBytes);
-			if (NumBytes != 0) {
-				IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
-				SK_RLMT_LOOKAHEAD(pAC, PortIndex, 
-					&pMsg->data[Offset],
-					IsBc, IsMc, &ForRlmt);
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
+		ForRlmt = SK_RLMT_RX_PROTOCOL;
+		IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+		SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
+			IsBc, &Offset, &NumBytes);
+		if (NumBytes != 0) {
+			IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+			SK_RLMT_LOOKAHEAD(pAC, PortIndex, 
+				&pMsg->data[Offset],
+				IsBc, IsMc, &ForRlmt);
+		}
+		if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
+					SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("W"));
+			/* send up only frames from active port */
+			if ((PortIndex == pAC->ActivePort) ||
+				(pAC->RlmtNets == 2)) {
+				/* frame for upper layer */
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U"));
+#ifdef xDEBUG
+				DumpMsg(pMsg, "Rx");
+#endif
+				SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
+					FrameLength, pRxPort->PortIndex);
+
+				pMsg->dev = pAC->dev[pRxPort->PortIndex];
+				pMsg->protocol = eth_type_trans(pMsg,
+					pAC->dev[pRxPort->PortIndex]);
+				netif_rx(pMsg);
+				pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
 			}
-			if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
-				/* send up only frames from active port */
-			    	if (PortIndex == pAC->ActivePort) {
-					/* frame for upper layer */
-					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
-						SK_DBGCAT_DRV_RX_PROGRESS,
-						("U"));
-#ifdef DUMP_RX
-					DumpMsg(pMsg, "Rx");
-#endif
-					pMsg->dev = pAC->dev;
-					pMsg->protocol = eth_type_trans(pMsg,
-						pAC->dev);
-					SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
-						FrameLength);
-					netif_rx(pMsg);
-					pAC->dev->last_rx = jiffies;
-				}
-				else {
-					/* drop frame */
-					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
-						SK_DBGCAT_DRV_RX_PROGRESS,
-						("D"));
-					DEV_KFREE_SKB_IRQ(pMsg);
-				}
-			} /* if not for rlmt */
 			else {
-				/* packet for rlmt */
+				/* drop frame */
 				SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
-					SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
-				pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
-					pAC->IoBase, FrameLength);
-				if (pRlmtMbuf != NULL) {
-					pRlmtMbuf->pNext = NULL;
-					pRlmtMbuf->Length = FrameLength;
-					pRlmtMbuf->PortIdx = PortIndex;
-					EvPara.pParaPtr = pRlmtMbuf;
-					memcpy((char*)(pRlmtMbuf->pData),
-					       (char*)(pMsg->data),
-					       FrameLength);
-					SkEventQueue(pAC, SKGE_RLMT,
-						SK_RLMT_PACKET_RECEIVED,
-						EvPara);
-					pAC->CheckQueue = SK_TRUE;
-					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
-						SK_DBGCAT_DRV_RX_PROGRESS,
-						("Q"));
-				}
-				if ((pAC->dev->flags & 
-					(IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
-					(ForRlmt & SK_RLMT_RX_PROTOCOL) == 
-					SK_RLMT_RX_PROTOCOL) { 
-					pMsg->dev = pAC->dev;
-					pMsg->protocol = eth_type_trans(pMsg,
-						pAC->dev);
-					netif_rx(pMsg);
-					pAC->dev->last_rx = jiffies;
-				}
-				else {
-					DEV_KFREE_SKB_IRQ(pMsg);
-				}
-
-			} /* if packet for rlmt */
-		} /* if valid frame */
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("D"));
+				DEV_KFREE_SKB(pMsg);
+			}
+			
+		} /* if not for rlmt */
 		else {
-			/* there is a receive error in this frame */
-			if ((FrameStat & XMR_FS_1L_VLAN) != 0) {
-				printk("%s: Received frame"
-					" with VLAN Level 1 header, check"
-					" switch configuration\n",
-					pAC->dev->name);
+			/* packet for rlmt */
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
+				SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
+			pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
+				pAC->IoBase, FrameLength);
+			if (pRlmtMbuf != NULL) {
+				pRlmtMbuf->pNext = NULL;
+				pRlmtMbuf->Length = FrameLength;
+				pRlmtMbuf->PortIdx = PortIndex;
+				EvPara.pParaPtr = pRlmtMbuf;
+				memcpy((char*)(pRlmtMbuf->pData),
+					   (char*)(pMsg->data),
+					   FrameLength);
+				SkEventQueue(pAC, SKGE_RLMT,
+					SK_RLMT_PACKET_RECEIVED,
+					EvPara);
+				pAC->CheckQueue = SK_TRUE;
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("Q"));
 			}
-			if ((FrameStat & XMR_FS_2L_VLAN) != 0) {
-				printk("%s: Received frame"
-					" with VLAN Level 2 header, check"
-					" switch configuration\n",
-					pAC->dev->name);
+			if ((pAC->dev[pRxPort->PortIndex]->flags & 
+				(IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
+				(ForRlmt & SK_RLMT_RX_PROTOCOL) == 
+				SK_RLMT_RX_PROTOCOL) { 
+				pMsg->dev = pAC->dev[pRxPort->PortIndex];
+				pMsg->protocol = eth_type_trans(pMsg,
+					pAC->dev[pRxPort->PortIndex]);
+				netif_rx(pMsg);
+				pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
 			}
-			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
-				SK_DBGCAT_DRV_RX_PROGRESS,
-				("skge: Error in received frame, dropped!\n"
-				"Control: %x\nRxStat: %x\n",
-				Control, FrameStat));
-			DEV_KFREE_SKB_IRQ(pMsg);
-		}
-	} /* while */
+			else {
+				DEV_KFREE_SKB(pMsg);
+			}
+
+		} /* if packet for rlmt */
+	} /* for ... scanning the RXD ring */
+
+	/* RXD ring is empty -> fill and restart */
 	FillRxRing(pAC, pRxPort);
 	/* do not start if called from Close */
 	if (pAC->BoardLevel > 0) {
@@ -2254,6 +2413,7 @@
 int	RxRam;		/* RAM used for the active port receive queue */
 int	i;		/* loop counter */
 
+if (pAC->RlmtNets == 1) {
 	StandbyRam = SK_RLMT_STANDBY_QRXSIZE + SK_RLMT_STANDBY_QXASIZE +
 		SK_RLMT_STANDBY_QXSSIZE;
 	RemainingRam = pAC->GIni.GIRamSize - 
@@ -2274,21 +2434,40 @@
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("queue sizes settings - rx:%d  txA:%d txS:%d\n",
 		pAC->RxQueueSize,pAC->TxAQueueSize, pAC->TxSQueueSize));
+} else {
+	RemainingRam = pAC->GIni.GIRamSize/pAC->GIni.GIMacsFound;
+	RxRam = (RemainingRam * 8 / 10) & ~7;
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		pAC->GIni.GP[i].PRxQSize = RxRam;
+		pAC->GIni.GP[i].PXSQSize = 0;
+		pAC->GIni.GP[i].PXAQSize = (RemainingRam - RxRam) & ~7;
+	}
 	
+	pAC->RxQueueSize = RxRam;
+	pAC->TxSQueueSize = 0;
+	pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7;
+}
 	for (i=0; i<SK_MAX_MACS; i++) {
 		pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing;
 	}
-	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-		pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100;
+
+	if (pAC->RlmtNets == 2) {
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100;
+		}
+	} else {
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100;
+		}
+		/*
+		 * Do not set the Limit to 0, because this could cause
+		 * wrap around with ReQueue'ed buffers (a buffer could
+		 * be requeued in the same position, made accessable to
+		 * the hardware, and the hardware could change its
+		 * contents!
+		 */
+		pAC->RxPort[pAC->ActivePort].RxFillLimit = 1;
 	}
-	/*
-	 * Do not set the Limit to 0, because this could cause
-	 * wrap around with ReQueue'ed buffers (a buffer could
-	 * be requeued in the same position, made accessable to
-	 * the hardware, and the hardware could change its
-	 * contents!
-	 */
-	pAC->RxPort[pAC->ActivePort].RxFillLimit = 1;
 
 #ifdef DEBUG
 	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
@@ -2316,7 +2495,10 @@
  */
 static int SkGeSetMacAddr(struct net_device *dev, void *p)
 {
-SK_AC		*pAC = (SK_AC*) dev->priv;
+
+DEV_NET *pNet = (DEV_NET*) dev->priv;
+SK_AC	*pAC = pNet->pAC;
+
 struct sockaddr	*addr = p;
 unsigned int	Flags;
 	
@@ -2328,8 +2510,15 @@
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
 	
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
-	SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
-		(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+
+	if (pAC->RlmtNets == 2)
+		SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr,
+			(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+	else
+		SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
+			(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+
+	
 	
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
 	return 0;
@@ -2352,37 +2541,47 @@
  */
 static void SkGeSetRxMode(struct net_device *dev)
 {
-SK_AC			*pAC;
+
+DEV_NET		*pNet;
+SK_AC		*pAC;
+
 struct dev_mc_list	*pMcList;
 int			i;
+int			PortIdx;
 unsigned int		Flags;
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeSetRxMode starts now... "));
-	pAC = (SK_AC*) dev->priv;
-	
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+	if (pAC->RlmtNets == 1)
+		PortIdx = pAC->ActivePort;
+	else
+		PortIdx = pNet->NetNr;
+
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
 	if (dev->flags & IFF_PROMISC) {
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 			("PROMISCUOUS mode\n"));
-		SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
 			SK_PROM_MODE_LLC);
 	} else if (dev->flags & IFF_ALLMULTI) {
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 			("ALLMULTI mode\n"));
-		SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
 			SK_PROM_MODE_ALL_MC);
 	} else {
-		SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
 			SK_PROM_MODE_NONE);
-		SkAddrMcClear(pAC, pAC->IoBase, pAC->ActivePort, 0);
+		SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
 
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 			("Number of MC entries: %d ", dev->mc_count));
 		
 		pMcList = dev->mc_list;
 		for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) {
-			SkAddrMcAdd(pAC, pAC->IoBase, pAC->ActivePort,
+			SkAddrMcAdd(pAC, pAC->IoBase, PortIdx,
 				(SK_MAC_ADDR*)pMcList->dmi_addr, 0);
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA,
 				("%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -2393,7 +2592,7 @@
 				pMcList->dmi_addr[4],
 				pMcList->dmi_addr[5]));
 		}
-		SkAddrMcUpdate(pAC, pAC->IoBase, pAC->ActivePort);					
+		SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx);
 	
 	}
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
@@ -2417,6 +2616,8 @@
  */
 static int SkGeChangeMtu(struct net_device *dev, int NewMtu)
 {
+DEV_NET		*pNet;
+DEV_NET		*pOtherNet;
 SK_AC		*pAC;
 unsigned int	Flags;
 int		i;
@@ -2424,30 +2625,58 @@
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeChangeMtu starts now...\n"));
- 
-	pAC = (SK_AC*) dev->priv;
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
+
 	if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) {
 		return -EINVAL;
 	}
 
+	pNet->Mtu = NewMtu;
+	pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv;
+	if ((pOtherNet->Mtu > 1500) && (NewMtu <= 1500) && (pOtherNet->Up==1)) {
+		return(0);
+	}
+
+	EvPara.Para32[0] = pNet->NetNr;
+	EvPara.Para32[1] = -1;
+
 	pAC->RxBufSize = NewMtu + 32;
 	dev->mtu = NewMtu;
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("New MTU: %d\n", NewMtu));
 
+	if(pAC->BoardLevel != 2) {
+		return 0;
+	}
+
 	/* prevent reconfiguration while changing the MTU */
 
 	/* disable interrupts */
 	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
-	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+
+	/* Found more than one port */
+	if ((pAC->GIni.GIMacsFound == 2 ) && 
+		(pAC->RlmtNets == 2)) {
+			/* Stop both ports */
+			EvPara.Para32[0] = 0;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+			EvPara.Para32[0] = 1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	} else {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	}
+
 	SkEventDispatcher(pAC, pAC->IoBase);
 
 	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-		spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+		spin_lock_irqsave(
+			&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags);
+		netif_stop_queue(pAC->dev[i]);
 	}
-	netif_stop_queue(pAC->dev);
 
 	/* 
 	 * adjust number of rx buffers allocated
@@ -2455,23 +2684,35 @@
 	if (NewMtu > 1500) {
 		/* use less rx buffers */
 		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-			if (i == pAC->ActivePort)
-				pAC->RxPort[i].RxFillLimit =
-					pAC->RxDescrPerRing - 100;
-			else
-				pAC->RxPort[i].RxFillLimit =
-					pAC->RxDescrPerRing - 10;
-
+			/* Found more than one port */
+			if ((pAC->GIni.GIMacsFound == 2 ) && 
+				(pAC->RlmtNets == 2)) {
+					pAC->RxPort[i].RxFillLimit = 
+						pAC->RxDescrPerRing - 100;
+			} else {
+				if (i == pAC->ActivePort)
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 100;
+				else
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 10;
+			}
 		}
 	}
 	else {
 		/* use normal anoumt of rx buffers */
 		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-			if (i == pAC->ActivePort)
-				pAC->RxPort[i].RxFillLimit = 1;
-			else
-				pAC->RxPort[i].RxFillLimit =
-					pAC->RxDescrPerRing - 100;
+			/* Found more than one port */
+			if ((pAC->GIni.GIMacsFound == 2 ) && 
+				(pAC->RlmtNets == 2)) {
+					pAC->RxPort[i].RxFillLimit = 1;
+			} else {
+				if (i == pAC->ActivePort)
+					pAC->RxPort[i].RxFillLimit = 1;
+				else
+					pAC->RxPort[i].RxFillLimit =
+						pAC->RxDescrPerRing - 100;
+			}
 		}
 	}
 	 
@@ -2481,6 +2722,7 @@
 	 * enable/disable hardware support for long frames
 	 */
 	if (NewMtu > 1500) {
+//		pAC->JumboActivated = SK_TRUE; /* is never set back !!! */
 		pAC->GIni.GIPortUsage = SK_JUMBO_LINK;
 		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
 			pAC->GIni.GP[i].PRxCmd = 
@@ -2488,10 +2730,14 @@
 		}
 	}
 	else {
-		pAC->GIni.GIPortUsage = SK_RED_LINK;
+		if ((pAC->GIni.GIMacsFound == 2 ) && 
+			(pAC->RlmtNets == 2)) {
+			pAC->GIni.GIPortUsage = SK_MUL_LINK;
+		} else {
+			pAC->GIni.GIPortUsage = SK_RED_LINK;
+		}
 		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-			pAC->GIni.GP[i].PRxCmd =
-				XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+			pAC->GIni.GP[i].PRxCmd = XM_RX_STRIP_FCS;
 		}
 	}
 
@@ -2519,7 +2765,7 @@
 		ClearRxRing(pAC, &pAC->RxPort[i]);
 		FillRxRing(pAC, &pAC->RxPort[i]);
 
-		// Enable transmit descriptor polling.
+		/* Enable transmit descriptor polling. */
 		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
 		FillRxRing(pAC, &pAC->RxPort[i]);
 	};
@@ -2536,7 +2782,7 @@
 	}
 #endif
 
-	netif_start_queue(pAC->dev);
+	netif_start_queue(pAC->dev[pNet->PortNr]);
 	for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) {
 		spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
 	}
@@ -2548,7 +2794,30 @@
 	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
 	SkEventDispatcher(pAC, pAC->IoBase);
 
+	/* Found more than one port */
+	if ((pAC->GIni.GIMacsFound == 2 ) && 
+		(pAC->RlmtNets == 2)) {
+			/* Start both ports */
+			EvPara.Para32[0] = pAC->RlmtNets;
+			EvPara.Para32[1] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+				EvPara);
+			
+			
+			EvPara.Para32[1] = -1;
+			EvPara.Para32[0] = pNet->PortNr;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+			
+			if (pOtherNet->Up) {
+				EvPara.Para32[0] = pOtherNet->PortNr;
+				SkEventQueue(pAC, SKGE_RLMT, 
+					SK_RLMT_START, EvPara);
+			}
+	} else {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	}
 
+	SkEventDispatcher(pAC, pAC->IoBase);
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
 	
 	return 0;
@@ -2568,7 +2837,8 @@
  */
 static struct net_device_stats *SkGeStats(struct net_device *dev)
 {
-SK_AC	*pAC = (SK_AC*) dev->priv;
+DEV_NET *pNet = (DEV_NET*) dev->priv;
+SK_AC	*pAC = pNet->pAC;
 SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
 SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
 unsigned int    Size;                   /* size of pnmi struct */
@@ -2580,7 +2850,7 @@
         memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA));
         spin_lock_irqsave(&pAC->SlowPathLock, Flags);
         Size = SK_PNMI_STRUCT_SIZE;
-        SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size);
+		SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr);
         spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
         pPnmiStat = &pPnmiStruct->Stat[0];
         pPnmiConf = &pPnmiStruct->Conf[0];
@@ -2622,7 +2892,7 @@
  * Description:
  *	This function is called if an ioctl is issued on the device.
  *	There are three subfunction for reading, writing and test-writing
- *	the private MIB data structure (useful for SysKonnect-internal tools).
+ *	the private MIB data structure (usefull for SysKonnect-internal tools).
  *
  * Returns:
  *	0, if everything is ok
@@ -2630,14 +2900,18 @@
  */
 static int SkGeIoctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+DEV_NET		*pNet;
 SK_AC		*pAC;
+
 SK_GE_IOCTL	Ioctl;
 unsigned int	Err = 0;
 int		Size;
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeIoctl starts now...\n"));
-	pAC = (SK_AC*) dev->priv;
+
+	pNet = (DEV_NET*) dev->priv;
+	pAC = pNet->pAC;
 	
 	if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) {
 		return -EFAULT;
@@ -2653,7 +2927,7 @@
 			Ioctl.Len : sizeof(pAC->PnmiStruct))) {
 			return -EFAULT;
 		}
-		Size = SkGeIocMib(pAC, Ioctl.Len, cmd);
+		Size = SkGeIocMib(pNet, Ioctl.Len, cmd);
 		if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct,
 			Ioctl.Len<Size? Ioctl.Len : Size)) {
 			return -EFAULT;
@@ -2688,25 +2962,30 @@
  *	returned size from PNMI call
  */
 static int SkGeIocMib(
-SK_AC		*pAC,	/* pointer to the adapter context */
+DEV_NET		*pNet,	/* pointer to the adapter context */
 unsigned int	Size,	/* length of ioctl data */
 int		mode)	/* flag for set/preset */
 {
 unsigned int	Flags;	/* for spin lock */
-	
+SK_AC		*pAC;
+
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeIocMib starts now...\n"));
+	pAC = pNet->pAC;
 	/* access MIB */
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
 	switch(mode) {
 	case SK_IOCTL_GETMIB:
-		SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size);
+		SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
 		break;
 	case SK_IOCTL_PRESETMIB:
-		SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size);
+		SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
 		break;
 	case SK_IOCTL_SETMIB:
-		SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size);
+		SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
 		break;
 	default:
 		break;
@@ -2780,7 +3059,7 @@
 			AutoNeg = AN_SENS;
 		}
 		else printk("%s: Illegal value for AutoNeg_A\n",
-			pAC->dev->name);
+			pAC->dev[0]->name);
 	}
 
 	DuplexCap = DC_BOTH;
@@ -2801,18 +3080,18 @@
 			DuplexCap = DC_HALF;
 		}
 		else printk("%s: Illegal value for DupCap_A\n",
-			pAC->dev->name);
+			pAC->dev[0]->name);
 	}
 	
 	/* check for illegal combinations */
 	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
 		printk("%s, Port A: DuplexCapabilities"
-			" ignored using Sense mode\n", pAC->dev->name);
+			" ignored using Sense mode\n", pAC->dev[0]->name);
 	}
 	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
 		printk("%s, Port A: Illegal combination"
 			" of values AutoNeg. and DuplexCap.\n    Using "
-			"Full Duplex\n", pAC->dev->name);
+			"Full Duplex\n", pAC->dev[0]->name);
 
 		DuplexCap = DC_FULL;
 	}
@@ -2824,7 +3103,7 @@
 		printk("%s, Port A: Duplex setting not"
 			" possible in\n    default AutoNegotiation mode"
 			" (Sense).\n    Using AutoNegotiation On\n",
-			pAC->dev->name);
+			pAC->dev[0]->name);
 		AutoNeg = AN_ON;
 	}
 	
@@ -2859,7 +3138,7 @@
 		SK_FLOW_MODE_NONE) {
 		printk("%s, Port A: FlowControl"
 			" impossible without AutoNegotiation,"
-			" disabled\n", pAC->dev->name);
+			" disabled\n", pAC->dev[0]->name);
 		pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_NONE;
 	}
 
@@ -2878,7 +3157,7 @@
 			MSMode = SK_MS_MODE_SLAVE;
 		}
 		else printk("%s: Illegal value for Role_A\n",
-			pAC->dev->name);
+			pAC->dev[0]->name);
 	}
 	pAC->GIni.GP[0].PMSMode = MSMode;
 	
@@ -2927,12 +3206,12 @@
 	/* check for illegal combinations */
 	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
 		printk("%s, Port B: DuplexCapabilities"
-			" ignored using Sense mode\n", pAC->dev->name);
+			" ignored using Sense mode\n", pAC->dev[1]->name);
 	}
 	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
 		printk("%s, Port B: Illegal combination"
 			" of values AutoNeg. and DuplexCap.\n    Using "
-			"Full Duplex\n", pAC->dev->name);
+			"Full Duplex\n", pAC->dev[1]->name);
 
 		DuplexCap = DC_FULL;
 	}
@@ -2944,14 +3223,14 @@
 		printk("%s, Port B: Duplex setting not"
 			" possible in\n    default AutoNegotiation mode"
 			" (Sense).\n    Using AutoNegotiation On\n",
-			pAC->dev->name);
+			pAC->dev[1]->name);
 		AutoNeg = AN_ON;
 	}
-	
+
 	/* set the desired mode */
 	pAC->GIni.GP[1].PLinkModeConf =
 		Capabilities[AutoNeg][DuplexCap];
-	
+
 	pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
 	if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
 		FlowCtrl_B[pAC->Index] != NULL) {
@@ -2979,7 +3258,7 @@
 		SK_FLOW_MODE_NONE) {
 		printk("%s, Port B: FlowControl"
 			" impossible without AutoNegotiation,"
-			" disabled\n", pAC->dev->name);
+			" disabled\n", pAC->dev[1]->name);
 		pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_NONE;
 	}
 
@@ -2998,7 +3277,7 @@
 			MSMode = SK_MS_MODE_SLAVE;
 		}
 		else printk("%s: Illegal value for Role_B\n",
-			pAC->dev->name);
+			pAC->dev[1]->name);
 	}
 	pAC->GIni.GP[1].PMSMode = MSMode;
 	
@@ -3009,8 +3288,8 @@
 		PrefPort[pAC->Index] != NULL) {
 		if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */
 			pAC->ActivePort = 0;
-			pAC->Rlmt.MacPreferred = -1; /* auto */
-			pAC->Rlmt.PrefPort = 0;
+			pAC->Rlmt.Net[0].Preference = -1; /* auto */
+			pAC->Rlmt.Net[0].PrefPort = 0;
 		}
 		else if (strcmp(PrefPort[pAC->Index],"A") == 0) {
 			/*
@@ -3018,8 +3297,8 @@
 			 * switch is issued after net up.
 			 */
 			Port = 0;
-			pAC->Rlmt.MacPreferred = Port;
-			pAC->Rlmt.PrefPort = Port;
+			pAC->Rlmt.Net[0].Preference = Port;
+			pAC->Rlmt.Net[0].PrefPort = Port;
 		}
 		else if (strcmp(PrefPort[pAC->Index],"B") == 0) {
 			/*
@@ -3027,12 +3306,14 @@
 			 * switch is issued after net up.
 			 */
 			Port = 1;
-			pAC->Rlmt.MacPreferred = Port;
-			pAC->Rlmt.PrefPort = Port;
+			pAC->Rlmt.Net[0].Preference = Port;
+			pAC->Rlmt.Net[0].PrefPort = Port;
 		}
 		else printk("%s: Illegal value for PrefPort\n",
-			pAC->dev->name);
+			pAC->dev[0]->name);
 	}
+
+	pAC->RlmtNets = 1;
 	
 	if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
 		RlmtMode[pAC->Index] != NULL) {
@@ -3051,9 +3332,18 @@
 				SK_RLMT_CHECK_LOC_LINK | 
 				SK_RLMT_CHECK_SEG;
 		}
+		else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) &&
+			(pAC->GIni.GIMacsFound == 2)) {
+				pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+				pAC->RlmtNets = 2;
+		}
 		else {
 			printk("%s: Illegal value for"
-				" RlmtMode, using default\n", pAC->dev->name);
+				" RlmtMode, using default\n", pAC->dev[0]->name);
+
+printk("MacFound = %d\nRlmtMode = %s", pAC->GIni.GIMacsFound, RlmtMode[pAC->Index]);
+	
+
 			pAC->RlmtMode = 0;
 		}
 	}
@@ -3355,7 +3645,7 @@
 	case SK_DRV_ADAP_FAIL:
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
 			("ADAPTER FAIL EVENT\n"));
-		printk("%s: Adapter failed.\n", pAC->dev->name);
+		printk("%s: Adapter failed.\n", pAC->dev[0]->name);
 		/* disable interrupts */
 		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
 		/* cgoos */
@@ -3365,9 +3655,9 @@
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
 			("PORT FAIL EVENT, Port: %d\n", FromPort));
 		if (FromPort == 0) {
-			printk("%s: Port A failed.\n", pAC->dev->name);
+			printk("%s: Port A failed.\n", pAC->dev[0]->name);
 		} else {
-			printk("%s: Port B failed.\n", pAC->dev->name);
+			printk("%s: Port B failed.\n", pAC->dev[1]->name);
 		}
 		/* cgoos */
 		break;
@@ -3408,7 +3698,7 @@
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
 			("NET UP EVENT, Port: %d ", Param.Para32[0]));
 		printk("%s: network connection up using"
-			" port %c\n", pAC->dev->name, 'A'+Param.Para32[0]);
+			" port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]);
 		printk("    speed:           1000\n");
 		Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
 		if (Stat == SK_LMODE_STAT_AUTOHALF ||
@@ -3451,7 +3741,8 @@
 			}
 		}
 		
-		if (Param.Para32[0] != pAC->ActivePort) {
+		if ((Param.Para32[0] != pAC->ActivePort) && 
+			(pAC->RlmtNets == 1)) {
 			NewPara.Para32[0] = pAC->ActivePort;
 			NewPara.Para32[1] = Param.Para32[0];
 			SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
@@ -3462,21 +3753,21 @@
 		/* action list 7 */
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
 			("NET DOWN EVENT "));
-		printk("%s: network connection down\n", pAC->dev->name);
+		printk("%s: network connection down\n", pAC->dev[Param.Para32[1]]->name);
 		break;
 	case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
 			("PORT SWITCH HARD "));
 	case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
 	/* action list 6 */
-		printk("%s: switching to port %c\n", pAC->dev->name,
+		printk("%s: switching to port %c\n", pAC->dev[0]->name,
 			'A'+Param.Para32[1]);
 	case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
 		FromPort = Param.Para32[0];
 		ToPort = Param.Para32[1];
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
 			("PORT SWITCH EVENT, From: %d  To: %d (Pref %d) ",
-			FromPort, ToPort, pAC->Rlmt.PrefPort));
+			FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort));
 		NewPara.Para64 = FromPort;
 		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
 		NewPara.Para64 = ToPort;
@@ -3591,7 +3882,7 @@
 		break;
 	}
 	printk(KERN_INFO "%s: -- ERROR --\n        Class:  %s\n"
-		"        Nr:  0x%x\n        Msg:  %s\n", pAC->dev->name,
+		"        Nr:  0x%x\n        Msg:  %s\n", pAC->dev[0]->name,
 		ClassStr, ErrNum, pErrorMsg);
 
 } /* SkErrorLog */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgehwt.c linux/drivers/net/sk98lin/skgehwt.c
--- v2.4.6/linux/drivers/net/sk98lin/skgehwt.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skgehwt.c	Wed Jul  4 11:50:39 2001
@@ -1,23 +1,32 @@
 /******************************************************************************
  *
  * Name:	skgehwt.c
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.13 $
- * Date:	$Date: 1999/11/22 13:31:12 $
+ * Project:	PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1998/10/15 15:11:34 $
  * Purpose:	Hardware Timer.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1989-1998 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	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; either version 2 of the License, or
- *	(at your option) any later version.
- *
+ *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
+ *	The copyright notice above does not evidence any
+ *	actual or intended publication of such source code.
+ *
+ *	This Module contains Proprietary Information of SysKonnect
+ *	and should be treated as Confidential.
+ *
+ *	The information in this file is provided for the exclusive use of
+ *	the licensees of SysKonnect.
+ *	Such users have the right to use, modify, and incorporate this code
+ *	into products for purposes authorized by the license agreement
+ *	provided they include this notice and the associated copyright notice
+ *	with any such product.
  *	The information in this file is provided "AS IS" without warranty.
  *
  ******************************************************************************/
@@ -27,9 +36,6 @@
  * History:
  *
  *	$Log: skgehwt.c,v $
- *	Revision 1.13  1999/11/22 13:31:12  cgoos
- *	Changed license header to GPL.
- *	
  *	Revision 1.12  1998/10/15 15:11:34  gklug
  *	fix: ID_sccs to SysKonnectFileId
  *	
@@ -77,7 +83,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.13 1999/11/22 13:31:12 cgoos Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.12 1998/10/15 15:11:34 gklug Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgeinit.c linux/drivers/net/sk98lin/skgeinit.c
--- v2.4.6/linux/drivers/net/sk98lin/skgeinit.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/skgeinit.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgeinit.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.57 $
- * Date:	$Date: 2000/08/03 14:55:28 $
+ * Version:	$Revision: 1.63 $
+ * Date:	$Date: 2001/04/05 11:02:09 $
  * Purpose:	Contains functions to initialize the GE HW
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,24 @@
  * History:
  *
  *	$Log: skgeinit.c,v $
+ *	Revision 1.63  2001/04/05 11:02:09  rassmann
+ *	Stop Port check of the STOP bit did not take 2/18 sec as wanted.
+ *	
+ *	Revision 1.62  2001/02/07 07:54:21  rassmann
+ *	Corrected copyright.
+ *	
+ *	Revision 1.61  2001/01/31 15:31:40  gklug
+ *	fix: problem with autosensing an SR8800 switch
+ *	
+ *	Revision 1.60  2000/10/18 12:22:21  cgoos
+ *	Added workaround for half duplex hangup.
+ *	
+ *	Revision 1.59  2000/10/10 11:22:06  gklug
+ *	add: in manual half duplex mode ignore carrier extension errors
+ *	
+ *	Revision 1.58  2000/10/02 14:10:27  rassmann
+ *	Reading BCOM PHY after releasing reset until it returns a valid value.
+ *	
  *	Revision 1.57  2000/08/03 14:55:28  rassmann
  *	Waiting for I2C to be ready before de-initializing adapter
  *	(prevents sensors from hanging up).
@@ -122,7 +139,7 @@
  *	chg: Default is autosensing with AUTOFULL mode
  *
  *	Revision 1.31  1998/11/25 15:36:16  gklug
- *	fix: do NOT stop LED Timer when port should be stopped
+ *	fix: do NOT stop LED Timer when port should be stoped
  *
  *	Revision 1.30  1998/11/24 13:15:28  gklug
  *	add: Init PCkeckPar struct member
@@ -283,7 +300,7 @@
 /* local variables ************************************************************/
 
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skgeinit.c,v 1.57 2000/08/03 14:55:28 rassmann Exp $ (C) SK ";
+	"@(#)$Id: skgeinit.c,v 1.63 2001/04/05 11:02:09 rassmann Exp $ (C) SK ";
 
 struct s_QOffTab {
 	int	RxQOff;		/* Receive Queue Address Offset */
@@ -666,7 +683,11 @@
 	SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
 	SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
 
-	/* enable timeout timers if jumbo frames not used */
+	/*
+	 * enable timeout timers if jumbo frames not used
+	 * NOTE: the packet arbiter timeout interrupt is needed for
+	 * half duplex hangup workaround
+	 */
 	if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
 		if (pAC->GIni.GIMacsFound == 1) {
 			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
@@ -1118,10 +1139,10 @@
  *
  *	Dir =	SK_STOP_TX 	Stops the transmit path only and resets
  *				the XMAC. The receive queue is still and
- *				the pending rx frames may still transferred
+ *				the pending rx frames may still transfered
  *				into the RxD.
  *		SK_STOP_RX	Stop the receive path. The tansmit path
- *				has to be stopped once before.
+ *				has to be stoped once before.
  *		SK_STOP_ALL	SK_STOP_TX + SK_STOP_RX
  *
  *	RstMode=SK_SOFT_RST	Resets the XMAC. The PHY is still alive.
@@ -1129,7 +1150,7 @@
  *
  * Example:
  *	1) A Link Down event was signaled for a port. Therefore the activity
- *	of this port should be stopped and a hardware reset should be issued
+ *	of this port should be stoped and a hardware reset should be issued
  *	to enable the workaround of XMAC errata #2. But the received frames
  *	should not be discarded.
  *		...
@@ -1198,10 +1219,10 @@
 	SK_U16	Word;
 	SK_U32	XsCsr;
 	SK_U32	XaCsr;
-	int	i;
+	int		i;
 	SK_BOOL	AllPortsDis;
 	SK_U64	ToutStart;
-	int	ToutCnt;
+	int		ToutCnt;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -1226,7 +1247,7 @@
 		do {
 			/*
 			 * Clear packet arbiter timeout to make sure
-			 * this loop will terminate
+			 * this loop will terminate.
 			 */
 			if (Port == MAC_1) {
 				Word = PA_CLR_TO_TX1;
@@ -1237,9 +1258,8 @@
 			SK_OUT16(IoC, B3_PA_CTRL, Word);
 
 			/*
-			 * If the transfer stucks at the XMAC the STOP command
-			 * will not terminate if we don't flush the XMACs
-			 * transmit FIFO !
+			 * If the transfer stucks at the XMAC the STOP command will not
+			 * terminate if we don't flush the XMAC's transmit FIFO!
 			 */
 			XM_IN32(IoC, Port, XM_MODE, &DWord);
 			DWord |= XM_MD_FTF;
@@ -1248,7 +1268,7 @@
 			XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
 			XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
 
-			if (ToutStart + (SK_TICKS_PER_SEC / 18) >= SkOsGetTime(pAC)) {
+			if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
 				/*
 				 * Timeout of 1/18 second reached.
 				 * This needs to be checked at 1/18 sec only.
@@ -1257,9 +1277,8 @@
 				switch (ToutCnt) {
 				case 1:
 					/*
-					 * Cache Incoherency workaround:
-					 * Assume a start command has been 
-					 * lost while sending the frame. 
+					 * Cache Incoherency workaround: Assume a start command
+					 * has been lost while sending the frame. 
 					 */
 					ToutStart = SkOsGetTime(pAC);
 					if (XsCsr & CSR_STOP) {
@@ -1275,6 +1294,7 @@
 					 * calls StopPort again.
 					 * XXX.
 					 */
+
 					/* Fatal Error, Loop aborted */
 					/* Create an Error Log Entry */
 					SK_ERR_LOG(
@@ -1290,12 +1310,12 @@
 				}
 			}
 
-		/*
-		 * Because of the ASIC problem report entry from 21.08.1998 it is
-		 * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
-		 */
-		} while ((XsCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE ||
-			 (XaCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE);
+			/*
+			 * Because of the ASIC problem report entry from 21.08.1998 it is
+			 * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
+			 */
+		} while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE ||
+			 (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
 
 		/* reset the XMAC depending on the RstMode */
 		if (RstMode == SK_SOFT_RST) {
@@ -1362,13 +1382,13 @@
 				i--;
 			}
 
-		/* finish if CSR_STOP is done or CSR_SV_IDLE is true and i==0 */
-		/*
-		 * because of the ASIC problem report entry from 21.08.98
-		 * it is required to wait until CSR_STOP is reset and
-		 * CSR_SV_IDLE is set.
-		 */
-		} while ((DWord & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE &&
+			/* finish if CSR_STOP is done or CSR_SV_IDLE is true and i==0 */
+			/*
+			 * because of the ASIC problem report entry from 21.08.98
+			 * it is required to wait until CSR_STOP is reset and
+			 * CSR_SV_IDLE is set.
+			 */
+		} while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE &&
 			((DWord & CSR_SV_IDLE) == 0 || i != 0));
 
 		/* The path data transfer activity is fully stopped now. */
@@ -1433,6 +1453,7 @@
 		pPrt->PIsave = 0;
 		pPrt->PPrevShorts = 0;
 		pPrt->PLinkResCt = 0;
+		pPrt->PAutoNegTOCt = 0;
 		pPrt->PPrevRx = 0;
 		pPrt->PPrevFcs = 0;
 		pPrt->PRxLim = SK_DEF_RX_WA_LIM;
@@ -1717,6 +1738,17 @@
 		if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
 			pPrt->PRxCmd |= XM_RX_BIG_PK_OK;
 		}
+
+		if (pPrt->PLinkModeConf == SK_LMODE_HALF) {
+			/*
+			 * If in manual half duplex mode
+			 * the other side might be in full duplex mode
+			 * so ignore if a carrier extension is not seen on
+			 * frames received
+			 */
+			pPrt->PRxCmd |= XM_RX_DIS_CEXT;
+		}
+
 	}
 }	/* SkGeInit2 */
 
@@ -1891,7 +1923,7 @@
  *		for PRxQSize, PXSQSize, or PXAQSize are invalid for one
  *		or more queues. The specified port was NOT initialized.
  *		An error log entry was generated.
- *	2:	The port has to be stopped before it can be initilaized again.
+ *	2:	The port has to be stopped before it can be initialized again.
  */
 int SkGeInitPort(
 SK_AC	*pAC,		/* adapter context */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgepnmi.c linux/drivers/net/sk98lin/skgepnmi.c
--- v2.4.6/linux/drivers/net/sk98lin/skgepnmi.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/skgepnmi.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgepnmi.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.78 $
- * Date:	$Date: 2000/09/12 10:44:58 $
+ * Version:	$Revision: 1.87 $
+ * Date:	$Date: 2001/04/06 13:35:09 $
  * Purpose:	Private Network Management Interface
  *
  ****************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,37 @@
  * History:
  *
  *	$Log: skgepnmi.c,v $
+ *	Revision 1.87  2001/04/06 13:35:09  mkunz
+ *	-Bugs fixed in handling of OID_SKGE_MTU and the VPD OID's
+ *	
+ *	Revision 1.86  2001/03/09 09:18:03  mkunz
+ *	Changes in SK_DBG_MSG
+ *	
+ *	Revision 1.85  2001/03/08 09:37:31  mkunz
+ *	Bugfix in ResetCounter for Pnmi.Port structure
+ *	
+ *	Revision 1.84  2001/03/06 09:04:55  mkunz
+ *	Made some changes in instance calculation
+ *	C	^VS:
+ *	
+ *	Revision 1.83  2001/02/15 09:15:32  mkunz
+ *	Necessary changes for dual net mode added
+ *	
+ *	Revision 1.82  2001/02/07 08:24:19  mkunz
+ *	-Made changes in handling of OID_SKGE_MTU
+ *	
+ *	Revision 1.81  2001/02/06 09:58:00  mkunz
+ *	-Vpd bug fixed
+ *	-OID_SKGE_MTU added
+ *	-pnmi support for dual net mode. Interface function and macros extended
+ *	
+ *	Revision 1.80  2001/01/22 13:41:35  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
+ *	Revision 1.79  2000/12/05 14:57:40  cgoos
+ *	SetStruct failed before first Link Up (link mode of virtual
+ *	port "INDETERMINATED").
+ *	
  *	Revision 1.78  2000/09/12 10:44:58  cgoos
  *	Fixed SK_PNMI_STORE_U32 calls with typecasted argument.
  *	
@@ -72,7 +102,7 @@
  *	
  *	Revision 1.67  1999/09/22 09:53:20  rwahl
  *	- Read Broadcom register for updating fcs error counter (1000Base-T).
- *	
+ *
  *	Revision 1.66  1999/08/26 13:47:56  rwahl
  *	Added SK_DRIVER_SENDEVENT when queueing RLMT_CHANGE_THRES trap.
  *	
@@ -81,7 +111,7 @@
  *	
  *	Revision 1.64  1999/05/20 09:24:12  cgoos
  *	Changes for 1000Base-T (sensors, Master/Slave).
- *	
+ *
  *	Revision 1.63  1999/04/13 15:11:58  mhaveman
  *	Moved include of rlmt.h to header skgepnmi.h because some macros
  *	are needed there.
@@ -149,7 +179,7 @@
  *	Fixed: Couldnot delete VPD keys on UNIX.
  *	
  *	Revision 1.48  1998/12/09 14:11:10  mhaveman
- *	-Add: Debugmessage for XMAC_RESET suppressed to minimize output.
+ *	-Add: Debugmessage for XMAC_RESET supressed to minimize output.
  *	-Fixed: RlmtChangeThreshold will now be initialized.
  *	-Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char.
  *	-Fixed: On VPD key creation an invalid key name could be created
@@ -185,7 +215,7 @@
  *	Revision 1.43  1998/12/03 14:18:10  mhaveman
  *	-Fixed problem in PnmiSetStruct. It was impossible to set any value.
  *	-Removed VPD key evaluation for VPD_FREE_BYTES and VPD_ACTION.
- *	
+ *
  *	Revision 1.42  1998/12/03 11:31:47  mhaveman
  *	Inserted cast to satisfy lint.
  *	
@@ -206,7 +236,7 @@
  *	-Fixed bug for RX counters. On an RX overflow interrupt the high
  *	 words of all RX counters were incremented.
  *	-SET operations on FLOWCTRL_MODE and LINK_MODE accept now the
- *	 value 0, which has no effect. It is useful for multiple instance
+ *	 value 0, which has no effect. It is usefull for multiple instance
  *	 SETs.
  *	
  *	Revision 1.37  1998/11/20 08:02:04  mhaveman
@@ -220,7 +250,7 @@
  *	
  *	Revision 1.35  1998/11/16 07:45:34  mhaveman
  *	SkAddrOverride now returns value and will be checked.
- *	
+ *
  *	Revision 1.34  1998/11/10 13:40:37  mhaveman
  *	Needed to change interface, because NT driver needs a return value
  *	of needed buffer space on TOO_SHORT errors. Therefore all
@@ -240,7 +270,7 @@
  *	Revision 1.30  1998/11/03 12:04:46  mhaveman
  *	Fixed problem in SENSOR_VALUE, which wrote beyond the buffer end
  *	Fixed alignment problem with CHIPSET.
- *	
+ *
  *	Revision 1.29  1998/11/02 11:23:54  mhaveman
  *	Corrected SK_ERROR_LOG to SK_ERR_LOG. Sorry.
  *	
@@ -270,14 +300,14 @@
  *	-Fixed sequence of error return code (INSTANCE -> ACCESS -> SHORT)
  *	-Changed type of parameter Instance back to SK_U32 because of VPD
  *	-Updated new VPD function calls
- *	
+ *
  *	Revision 1.23  1998/10/23 10:16:37  mhaveman
  *	Fixed bugs after buffer test simulation.
  *	
  *	Revision 1.22  1998/10/21 13:23:52  mhaveman
  *	-Call syntax of SkOsGetTime() changed to SkOsGetTime(pAc).
  *	-Changed calculation of hundrets of seconds.
- *	
+ *
  *	Revision 1.20  1998/10/20 07:30:45  mhaveman
  *	Made type changes to unsigned integer where possible.
  *	
@@ -291,12 +321,12 @@
  *	 to HWACCESS.
  *	-Provided all MEMCPY/MEMSET macros with (char *) pointers, because
  *	 Solaris throwed warnings when mapping to bcopy/bset.
- *	
+ *
  *	Revision 1.17  1998/10/13 07:42:01  mhaveman
  *	-Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA
  *	-Removed old cvs history entries
  *	-Renamed MacNumber to PortNumber
- *	
+ *
  *	Revision 1.16  1998/10/07 10:52:49  mhaveman
  *	-Inserted handling of some OID_GEN_ Ids for windows
  *	-Fixed problem with 803.2 statistic.
@@ -332,7 +362,7 @@
 
 
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skgepnmi.c,v 1.78 2000/09/12 10:44:58 cgoos Exp $"
+	"@(#) $Id: skgepnmi.c,v 1.87 2001/04/06 13:35:09 mkunz Exp $"
 	" (C) SysKonnect.";
 
 #include "h/skdrv1st.h"
@@ -356,14 +386,17 @@
  */
 int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
 int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
-	unsigned int *pLen, SK_U32 Instance);
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
-	unsigned int *pLen, SK_U32 Instance);
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
-	unsigned int *pLen, SK_U32 Instance);
-int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen);
-int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen);
-int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen);
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, 
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, 
+	unsigned int *pLen, SK_U32 NetIndex);
 int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
 
 
@@ -372,7 +405,7 @@
  */
 static int Addr(SK_AC *pAC, SK_IOC IoC, int action,
 	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
 	PhysPortIndex);
 static SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
@@ -381,14 +414,14 @@
 static void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
 static int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
 	unsigned int PhysPortIndex, unsigned int StatIndex);
 static SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
-	unsigned int StatIndex);
+	unsigned int StatIndex, SK_U32 NetIndex);
 static char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
 static void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
 	unsigned int *pEntries);
@@ -397,50 +430,50 @@
 static int LookupId(SK_U32 Id);
 static int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
 	unsigned int LastMac);
 static int Monitor(SK_AC *pAC, SK_IOC IoC, int action,
 	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int* pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
-	unsigned int *pLen);
+	unsigned int *pLen, SK_U32 NetIndex);
 static int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
-	char *pBuf, unsigned int *pLen, SK_U32 Instance);
+	char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 static void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
 static void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
 	unsigned int PortIndex);
 static void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
 	unsigned int SensorIndex);
 static void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
-static void ResetCounter(SK_AC *pAC, SK_IOC IoC);
+static void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
 static int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
-static int RlmtUpdate(SK_AC *pAC, SK_IOC IoC);
+	unsigned int TableIndex, SK_U32 NetIndex);
+static int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
 static int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 static int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
 static void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
 static int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 	char *pBuf, unsigned int *pLen, SK_U32 Instance,
-	unsigned int TableIndex);
+	unsigned int TableIndex, SK_U32 NetIndex);
 
 
 /******************************************************************************
@@ -1323,11 +1356,16 @@
 		sizeof(SK_PNMI_RLMT_MONITOR),
 		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin),
 		SK_PNMI_RW, Monitor, 0},
+	{OID_SKGE_MTU,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MtuSize),
+		SK_PNMI_RW, MacPrivateConf, 0},
 };
 
 /*
  * Table for hardware register saving on resets and port switches
-*/
+ */
 static const SK_PNMI_STATADDR StatAddress[SK_PNMI_MAX_IDX] = {
 	/*  0 */	{TRUE, XM_TXF_OK},
 	/*  1 */	{TRUE, 0},
@@ -1445,6 +1483,7 @@
 		for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {
 
 			pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
+			pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
 		}
 		break;
 
@@ -1600,7 +1639,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
  *	                         the data.
  *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
@@ -1615,14 +1654,15 @@
 SK_U32 Id,		/* Object ID that is to be processed */
 void *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
-SK_U32 Instance)	/* Instance (1..n) that is to be queried or -1 */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-		("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d\n", Id,
-		*pLen));
+		("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
 
 	return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
-		Instance));
+		Instance, NetIndex));
 }
 
 /*****************************************************************************
@@ -1632,13 +1672,13 @@
  * Description:
  *	Calls a general sub-function for all this stuff. The preset does
  *	the same as a set, but returns just before finally setting the
- *	new value. This is useful to check if a set might be successful.
+ *	new value. This is usefull to check if a set might be successfull.
  *	If as instance a -1 is passed, an array of values is supposed and
  *	all instance of the OID will be set.
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1657,14 +1697,16 @@
 SK_U32 Id,		/* Object ID that is to be processed */
 void *pBuf,		/* Buffer which stores the mgmt data to be set */
 unsigned int *pLen,	/* Total length of mgmt data */
-SK_U32 Instance)	/* Instance (1..n) that is to be set or -1 */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-		("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d\n",
-		Id, *pLen));
+		("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
 
 	return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
-		Instance));
+		Instance, NetIndex));
 }
 
 /*****************************************************************************
@@ -1674,13 +1716,13 @@
  * Description:
  *	Calls a general sub-function for all this stuff. The preset does
  *	the same as a set, but returns just before finally setting the
- *	new value. This is useful to check if a set might be successful.
+ *	new value. This is usefull to check if a set might be successfull.
  *	If as instance a -1 is passed, an array of values is supposed and
  *	all instance of the OID will be set.
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1699,14 +1741,15 @@
 SK_U32 Id,		/* Object ID that is to be processed */
 void *pBuf,		/* Buffer which stores the mgmt data to be set */
 unsigned int *pLen,	/* Total length of mgmt data */
-SK_U32 Instance)	/* Instance (1..n) that is to be set or -1 */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-		("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d\n", Id,
-		*pLen));
+		("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
 
 	return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
-		Instance));
+		Instance, NetIndex));
 }
 
 /*****************************************************************************
@@ -1723,16 +1766,18 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
  *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist 
  */
 
 int SkPnmiGetStruct(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 void *pBuf,		/* Buffer which will store the retrieved data */
-unsigned int *pLen)	/* Length of buffer */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int		Ret;
 	unsigned int	TableIndex;
@@ -1741,11 +1786,12 @@
 	unsigned int	InstanceCnt;
 	SK_U32		Instance;
 	unsigned int	TmpLen;
-	char		KeyArr[SK_PNMI_VPD_ARR_SIZE][SK_PNMI_VPD_STR_SIZE];
+	char		KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+
 
-	
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-		("PNMI: SkPnmiGetStruct: Called, BufLen=%d\n", *pLen));
+		("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
 
 	if (*pLen < SK_PNMI_STRUCT_SIZE) {
 
@@ -1759,6 +1805,13 @@
 		return (SK_PNMI_ERR_TOO_SHORT);
 	}
 
+    /*
+     * Check NetIndex
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+
 	/* Update statistic */
 	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");
 
@@ -1770,7 +1823,7 @@
 		return (Ret);
 	}
 
-	if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
 
 		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
 		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
@@ -1812,7 +1865,6 @@
 		TableIndex ++) {
 
 		InstanceNo = IdTable[TableIndex].InstanceNo;
-
 		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
 			InstanceCnt ++) {
 
@@ -1830,8 +1882,7 @@
 				IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
 				IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {
 
-				SK_PNMI_READ_U32(KeyArr[InstanceCnt - 1],
-					Instance);
+				SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4);
 			}
 			else {
 				Instance = (SK_U32)InstanceCnt;
@@ -1840,7 +1891,7 @@
 			TmpLen = *pLen - DstOffset;
 			Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
 				IdTable[TableIndex].Id, (char *)pBuf +
-				DstOffset, &TmpLen, Instance, TableIndex);
+				DstOffset, &TmpLen, Instance, TableIndex, NetIndex);
 
 			/*
 			 * An unknown instance error means that we reached
@@ -1850,7 +1901,7 @@
 			 */
 			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
 
-				break;
+                break;
 			}
 
 			if (Ret != SK_PNMI_ERR_OK) {
@@ -1884,7 +1935,7 @@
  * Description:
  *	Calls a general sub-function for all this set stuff. The preset does
  *	the same as a set, but returns just before finally setting the
- *	new value. This is useful to check if a set might be successful.
+ *	new value. This is usefull to check if a set might be successfull.
  *	The sub-function runs through the IdTable, checks which OIDs are able
  *	to set, and calls the handler function of the OID to perform the
  *	preset. The return value of the function will also be stored in
@@ -1893,7 +1944,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1905,12 +1956,15 @@
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 void *pBuf,		/* Buffer which contains the data to be set */
-unsigned int *pLen)	/* Length of buffer */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-		("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d\n", *pLen));
+		("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
 
-	return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf, pLen));
+	return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf, 
+    					pLen, NetIndex));
 }
 
 /*****************************************************************************
@@ -1929,7 +1983,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1941,12 +1995,15 @@
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 void *pBuf,		/* Buffer which contains the data to be set */
-unsigned int *pLen)	/* Length of buffer */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-		("PNMI: SkPnmiSetStruct: Called, BufLen=%d\n", *pLen));
+		("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
 
-	return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf, pLen));
+	return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf, 
+    					pLen, NetIndex));
 }
 
 /*****************************************************************************
@@ -1981,11 +2038,6 @@
  *	SK_PNMI_EVT_RLMT_PORT_DOWN    Generated by RLMT to notify that a port
  *	                              went logically down. A trap message will
  *	                              be stored to the trap buffer.
- *	SK_PNMI_EVT_RLMT_PORT_SWITCH  Generated by RLMT to notify that the
- *	                              active port switched. PNMI will split
- *	                              this into two message ACTIVE_DOWN and
- *	                              ACTIVE_UP to be future compatible with
- *	                              load balancing and card fail over.
  *	SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
  *	                              spanning tree root bridges were
  *	                              detected. A trap message will be stored
@@ -1997,6 +2049,9 @@
  *	                              is now an active port. PNMI will now
  *	                              add the statistic data of this port to
  *	                              the virtual port.
+ *	SK_PNMI_EVT_RLMT_SET_NETS     Notifies PNMI about the net mode. The first Parameter
+ *	                              contains the number of nets. 1 means single net, 2 means
+ *	                              dual net. The second Parameter is -1
  *
  * Returns:
  *	Always 0
@@ -2009,6 +2064,7 @@
 SK_EVPARA Param)	/* Event dependent parameter */
 {
 	unsigned int	PhysPortIndex;
+    unsigned int	MaxNetNumber;
 	int		CounterIndex;
 	int		Ret;
 	SK_U16		MacStatus;
@@ -2022,6 +2078,7 @@
 	SK_U64		OldestValue;
 	SK_U64		Delta;
 	SK_PNMI_ESTIMATE *pEst;
+	SK_U32		NetIndex;
 
 
 #ifdef DEBUG
@@ -2284,9 +2341,27 @@
 
 	case SK_PNMI_EVT_CLEAR_COUNTER:
 		/*
+		 *  Param.Para32[0] contains the NetIndex (0 ..1).
+		 *  Param.Para32[1] is reserved, contains -1.
+		 */
+		NetIndex = (SK_U32)Param.Para32[0];
+
+#ifdef DEBUG
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n",
+				NetIndex));
+
+			return (0);
+		}
+#endif
+
+		/*
 		 * Set all counters and timestamps to zero
 		 */
-		ResetCounter(pAC, IoC);
+		ResetCounter(pAC, IoC, NetIndex); /* the according NetIndex is required
+												as a Parameter of the Event */ 
 		break;
 
 	case SK_PNMI_EVT_XMAC_RESET:
@@ -2351,9 +2426,8 @@
 		}
 #endif
 		/*
-		 * Store a trap message in the trap buffer and generate
-		 * an event for user space applications with the
-		 * SK_DRIVER_SENDEVENT macro.
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
 		 */
 		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP,
 			(unsigned int)Param.Para32[0]);
@@ -2372,9 +2446,8 @@
 		}
 #endif
 		/*
-		 * Store a trap message in the trap buffer and generate
-		 * an event for user space applications with the
-		 * SK_DRIVER_SENDEVENT macro.
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
 		 */
 		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN,
 			(unsigned int)Param.Para32[0]);
@@ -2383,6 +2456,7 @@
 
 	case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
 		PhysPortIndex = (unsigned int)Param.Para32[0];
+		NetIndex = (SK_U32)Param.Para32[1];
 #ifdef DEBUG
 		if (PhysPortIndex >= SK_MAX_MACS) {
 
@@ -2390,8 +2464,23 @@
 				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
 				PhysPortIndex));
 		}
+
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n",
+				NetIndex));
+		}
 #endif
 		/*
+		 * For now, ignore event if NetIndex != 0.
+		 */
+		if (Param.Para32[1] != 0) {
+
+			return (0);
+		}
+
+		/*
 		 * Nothing to do if port is already inactive
 		 */
 		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
@@ -2400,9 +2489,9 @@
 		}
 
 		/*
-		 * Update statistic counters to calculate new offset
-		 * for the virtual port and increment semaphore to
-		 * indicate that an update was already done.
+		 * Update statistic counters to calculate new offset for the virtual
+		 * port and increment semaphore to indicate that an update was already
+		 * done.
 		 */
 		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
 			SK_PNMI_ERR_OK) {
@@ -2413,13 +2502,12 @@
 		pAC->Pnmi.MacUpdatedFlag ++;
 
 		/*
-		 * Calculate new counter offset for virtual port to
-		 * grant continous counting on port switches. The virtual
-		 * port consists of all currently active ports. The port
-		 * down event indicates that a port is removed fromt the
-		 * virtual port. Therefore add the counter value of the
-		 * removed port to the CounterOffset for the virtual port
-		 * to grant the same counter value.
+		 * Calculate new counter offset for virtual port to grant continous
+		 * counting on port switches. The virtual port consists of all currently
+		 * active ports. The port down event indicates that a port is removed
+		 * from the virtual port. Therefore add the counter value of the removed
+		 * port to the CounterOffset for the virtual port to grant the same
+		 * counter value.
 		 */
 		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
 			CounterIndex ++) {
@@ -2429,8 +2517,7 @@
 				continue;
 			}
 
-			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex,
-				CounterIndex);
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
 
 			pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
 		}
@@ -2445,6 +2532,7 @@
 
 	case SK_PNMI_EVT_RLMT_ACTIVE_UP:
 		PhysPortIndex = (unsigned int)Param.Para32[0];
+		NetIndex = (SK_U32)Param.Para32[1];
 #ifdef DEBUG
 		if (PhysPortIndex >= SK_MAX_MACS) {
 
@@ -2452,8 +2540,23 @@
 				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
 				PhysPortIndex));
 		}
+
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n",
+				NetIndex));
+		}
 #endif
 		/*
+		 * For now, ignore event if NetIndex != 0.
+		 */
+		if (Param.Para32[1] != 0) {
+
+			return (0);
+		}
+
+		/*
 		 * Nothing to do if port is already active
 		 */
 		if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
@@ -2462,24 +2565,22 @@
 		}
 
 		/*
-		 * Statistic maintanence
+		 * Statistic maintenance
 		 */
 		pAC->Pnmi.RlmtChangeCts ++;
-		pAC->Pnmi.RlmtChangeTime =
-			SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
 
 		/*
-		 * Store a trap message in the trap buffer and generate
-		 * an event for user space applications with the
-		 * SK_DRIVER_SENDEVENT macro.
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
 		 */
 		QueueRlmtNewMacTrap(pAC, PhysPortIndex);
 		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
 
 		/*
-		 * Update statistic counters to calculate new offset
-		 * for the virtual port and increment semaphore to indicate
-		 * that an update was already done.
+		 * Update statistic counters to calculate new offset for the virtual
+		 * port and increment semaphore to indicate that an update was
+		 * already done.
 		 */
 		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
 			SK_PNMI_ERR_OK) {
@@ -2490,11 +2591,10 @@
 		pAC->Pnmi.MacUpdatedFlag ++;
 
 		/*
-		 * Calculate new counter offset for virtual port to
-		 * grant continous counting on port switches. A new port
-		 * is added to the virtual port. Therefore substract the
-		 * counter value of the new port from the CounterOffset
-		 * for the virtual port to grant the same value.
+		 * Calculate new counter offset for virtual port to grant continous
+		 * counting on port switches. A new port is added to the virtual port.
+		 * Therefore substract the counter value of the new port from the
+		 * CounterOffset for the virtual port to grant the same value.
 		 */
 		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
 			CounterIndex ++) {
@@ -2504,8 +2604,7 @@
 				continue;
 			}
 
-			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex,
-				CounterIndex);
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
 
 			pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
 		}
@@ -2518,40 +2617,41 @@
 		pAC->Pnmi.MacUpdatedFlag --;
 		break;
 
-	case SK_PNMI_EVT_RLMT_PORT_SWITCH:
+	case SK_PNMI_EVT_RLMT_SEGMENTATION:
 		/*
-		 * This event becomes obsolete if RLMT generates directly
-		 * the events SK_PNMI_EVT_RLMT_ACTIVE_DOWN and
-		 * SK_PNMI_EVT_RLMT_ACTIVE_UP. The events are here emulated.
-		 * PNMI handles that multiple ports may become active. 
-		 * Increment semaphore to indicate that an update was
-		 * already done.
+		 * Para.Para32[0] contains the NetIndex.
 		 */
-		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
-			SK_PNMI_ERR_OK) {
-
-			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
-			return (0);
-		}
-		pAC->Pnmi.MacUpdatedFlag ++;
-
-		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Param);
-		Param.Para32[0] = Param.Para32[1];
-		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_RLMT_ACTIVE_UP, Param);
-
-		pAC->Pnmi.MacUpdatedFlag --;
-		break;
 
-	case SK_PNMI_EVT_RLMT_SEGMENTATION:
 		/*
-		 * Store a trap message in the trap buffer and generate
-		 * an event for user space applications with the
-		 * SK_DRIVER_SENDEVENT macro.
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
 		 */
 		QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
 		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
 		break;
 
+    case SK_PNMI_EVT_RLMT_SET_NETS:
+		/*
+		 *  Param.Para32[0] contains the number of Nets.
+		 *  Param.Para32[1] is reserved, contains -1.
+		 */
+	    /*
+    	 * Check number of nets
+		 */
+		MaxNetNumber = pAC->GIni.GIMacsFound;
+		if (((unsigned int)Param.Para32[0] < 1)
+			|| ((unsigned int)Param.Para32[0] > MaxNetNumber)) {
+			return (SK_PNMI_ERR_UNKNOWN_NET);
+		}
+
+        if((unsigned int)Param.Para32[0] == 1){ /* single net mode */
+        	pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+        }
+        else { /* dual net mode */
+        	pAC->Pnmi.DualNetActiveFlag = SK_TRUE;
+        }
+        break;
+
 	default:
 		break;
 	}
@@ -2580,6 +2680,7 @@
  * Returns:
  *	SK_PNMI_ERR_XXX. For details have a look to the description of the
  *	calling functions.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist 
  */
 
 static int PnmiVar(
@@ -2589,7 +2690,8 @@
 SK_U32 Id,		/* Object ID that is to be processed */
 char *pBuf,		/* Buffer which stores the mgmt data to be set */
 unsigned int *pLen,	/* Total length of mgmt data */
-SK_U32 Instance)	/* Instance (1..n) that is to be set or -1 */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	TableIndex;
 	int		Ret;
@@ -2600,11 +2702,18 @@
 		*pLen = 0;
 		return (SK_PNMI_ERR_UNKNOWN_OID);
 	}
+	
+    /* 
+     * Check NetIndex 
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
 
 	SK_PNMI_CHECKFLAGS("PnmiVar: On call");
 
 	Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
-		Instance, TableIndex);
+		Instance, TableIndex, NetIndex);
 
 	SK_PNMI_CHECKFLAGS("PnmiVar: On return");
 
@@ -2627,6 +2736,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_XXX. The codes are described in the calling functions.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist 
  */
 
 static int PnmiStruct(
@@ -2634,7 +2744,8 @@
 SK_IOC IoC,		/* IO context handle */
 int  Action,		/* Set action to be performed */
 char *pBuf,		/* Buffer which contains the data to be set */
-unsigned int *pLen)	/* Length of buffer */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int		Ret;
 	unsigned int	TableIndex;
@@ -2660,13 +2771,20 @@
 		return (SK_PNMI_ERR_TOO_SHORT);
 	}
 	
+    /* 
+     * Check NetIndex 
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+	
 	SK_PNMI_CHECKFLAGS("PnmiStruct: On call");
 
 	/*
 	 * Update the values of RLMT and SIRQ and increment semaphores to
 	 * indicate that an update was already done.
 	 */
-	if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
 
 		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
 		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
@@ -2716,7 +2834,7 @@
 			Len = 0;
 			Ret = IdTable[TableIndex].Func(pAC, IoC,
 				SK_PNMI_GET, IdTable[TableIndex].Id,
-				NULL, &Len, Instance, TableIndex);
+				NULL, &Len, Instance, TableIndex, NetIndex);
 
 			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
 
@@ -2754,7 +2872,7 @@
 			/* Call the OID handler function */
 			Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
 				IdTable[TableIndex].Id, pBuf + DstOffset,
-				&Len, Instance, TableIndex);
+				&Len, Instance, TableIndex, NetIndex);
 
 			if (Ret != SK_PNMI_ERR_OK) {
 
@@ -2816,7 +2934,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -2836,7 +2954,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	if (Id != OID_SKGE_ALL_DATA) {
 
@@ -2859,13 +2978,13 @@
 	switch (Action) {
 
 	case SK_PNMI_GET:
-		return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen));
+		return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex));
 
 	case SK_PNMI_PRESET:
-		return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen));
+		return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
 
 	case SK_PNMI_SET:
-		return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen));
+		return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
 	}
 
 	SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);
@@ -2883,7 +3002,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -2903,7 +3022,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int	Ret;
 	SK_U32	ActionOp;
@@ -2992,7 +3112,7 @@
 
 	case SK_PNMI_ACT_RESETCNT:
 		/* Set all counters and timestamps to zero */
-		ResetCounter(pAC, IoC);
+		ResetCounter(pAC, IoC, NetIndex);
 		break;
 
 	default:
@@ -3017,7 +3137,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3034,7 +3154,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex,	/* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int    Ret;
 	SK_U64 StatVal;
@@ -3080,7 +3201,7 @@
 		}
 
 #else /* SK_NDIS_64BIT_CTR */
-		
+
 		/*
 		 * for compatibility, at least 32bit are required for oid
 		 */
@@ -3092,7 +3213,7 @@
 			*pLen = sizeof(SK_U64);
 			return (SK_PNMI_ERR_TOO_SHORT);
 		}
-		
+
 		Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
 #endif /* SK_NDIS_64BIT_CTR */
 		break;
@@ -3117,17 +3238,17 @@
 	switch (Id) {
 
 	case OID_802_3_PERMANENT_ADDRESS:
-		CopyMac(pBuf, &pAC->Addr.PermanentMacAddress);
+		CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress);
 		*pLen = sizeof(SK_MAC_ADDR);
 		break;
 
 	case OID_802_3_CURRENT_ADDRESS:
-		CopyMac(pBuf, &pAC->Addr.CurrentMacAddress);
+		CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
 		*pLen = sizeof(SK_MAC_ADDR);
 		break;
 
 	default:
-		StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param);
+		StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex);
 
 		/*
 		 * by default 32bit values are evaluated
@@ -3159,7 +3280,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3176,7 +3297,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	LogPortMax;
 	unsigned int	LogPortIndex;
@@ -3194,22 +3316,28 @@
 	PhysPortMax = pAC->GIni.GIMacsFound;
 	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
 
-	if ((Instance != (SK_U32)(-1))) {
+	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */
+		LogPortMax--;
+	}
 
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
 		if ((Instance < 1) || (Instance > LogPortMax)) {
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_UNKNOWN_INST);
 		}
-
 		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
 		Limit = LogPortIndex + 1;
 	}
-	else {
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
 		LogPortIndex = 0;
 		Limit = LogPortMax;
 	}
 
+
 	/*
 	 * Check action
 	 */
@@ -3232,7 +3360,7 @@
 	 * Update XMAC statistic and increment semaphore to indicate that
 	 * an update was already done.
 	 */
-	Ret = MacUpdate(pAC, IoC, 0, PhysPortMax - 1);
+	Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
 	if (Ret != SK_PNMI_ERR_OK) {
 
 		*pLen = 0;
@@ -3264,15 +3392,15 @@
 		 */
 		case OID_SKGE_STAT_RX_TOO_LONG:
 			StatVal = GetStatVal(pAC, IoC, LogPortIndex,
-					     IdTable[TableIndex].Param) -
+					     IdTable[TableIndex].Param, NetIndex) -
 				GetStatVal(pAC, IoC, LogPortIndex,
-					   SK_PNMI_HRX_LONGFRAMES);
+					   SK_PNMI_HRX_LONGFRAMES, NetIndex);
 			SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
 			break;
 
 		default:
 			StatVal = GetStatVal(pAC, IoC, LogPortIndex,
-				IdTable[TableIndex].Param);
+				IdTable[TableIndex].Param, NetIndex);
 			SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
 			break;
 		}
@@ -3299,7 +3427,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3319,7 +3447,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int		Ret;
 	unsigned int	LogPortMax;
@@ -3330,24 +3459,31 @@
 	unsigned int	Offset = 0;
 
 
+
 	/*
-	 * Calculate instance if wished
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
 	 */
 	PhysPortMax = pAC->GIni.GIMacsFound;
 	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
 
-	if ((Instance != (SK_U32)(-1))) {
-		
+	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
 		if ((Instance < 1) || (Instance > LogPortMax)) {
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_UNKNOWN_INST);
 		}
-
 		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
 		Limit = LogPortIndex + 1;
 	}
-	else {
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
 		LogPortIndex = 0;
 		Limit = LogPortMax;
 	}
@@ -3375,34 +3511,28 @@
 
 			case OID_SKGE_PHYS_CUR_ADDR:
 				if (LogPortIndex == 0) {
-
-					CopyMac(pBuf + Offset, &pAC->Addr.
-						CurrentMacAddress);
+					CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
 				}
 				else {
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
 
-					CopyMac(pBuf + Offset, &pAC->Addr.
-						Port[PhysPortIndex].
-						CurrentMacAddress);
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Port[PhysPortIndex].CurrentMacAddress);
 				}
 				Offset += 6;
 				break;
 
 			case OID_SKGE_PHYS_FAC_ADDR:
 				if (LogPortIndex == 0) {
-
-					CopyMac(pBuf + Offset, &pAC->Addr.
-						PermanentMacAddress);
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Net[NetIndex].PermanentMacAddress);
 				}
 				else {
 					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
 						pAC, LogPortIndex);
 
-					CopyMac(pBuf + Offset, &pAC->Addr.
-						Port[PhysPortIndex].
-						PermanentMacAddress);
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Port[PhysPortIndex].PermanentMacAddress);
 				}
 				Offset += 6;
 				break;
@@ -3509,7 +3639,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3526,7 +3656,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	Index;
 	unsigned int	Limit;
@@ -3538,15 +3669,14 @@
 	 * Calculate instance if wished
 	 */
 	if (Instance != (SK_U32)(-1)) {
-		
+
 		if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_UNKNOWN_INST);
 		}
-
 		Index = (unsigned int)Instance - 1;
-		Limit = (unsigned int)Instance;
+		Limit = Index + 1;
 	}
 	else {
 		Index = 0;
@@ -3579,23 +3709,23 @@
 		switch (Id) {
 
 		case OID_SKGE_CHKSM_RX_OK_CTS:
-			StatVal = pAC->Csum.ProtoStats[Index].RxOkCts;
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts;
 			break;
 
 		case OID_SKGE_CHKSM_RX_UNABLE_CTS:
-			StatVal = pAC->Csum.ProtoStats[Index].RxUnableCts;
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts;
 			break;
 
 		case OID_SKGE_CHKSM_RX_ERR_CTS:
-			StatVal = pAC->Csum.ProtoStats[Index].RxErrCts;
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts;
 			break;
 
 		case OID_SKGE_CHKSM_TX_OK_CTS:
-			StatVal = pAC->Csum.ProtoStats[Index].TxOkCts;
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts;
 			break;
 
 		case OID_SKGE_CHKSM_TX_UNABLE_CTS:
-			StatVal = pAC->Csum.ProtoStats[Index].TxUnableCts;
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts;
 			break;
 
 		default:
@@ -3628,7 +3758,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3645,7 +3775,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	i;
 	unsigned int	Index;
@@ -3872,7 +4003,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3892,13 +4023,14 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_VPD_STATUS	*pVpdStatus;
 	unsigned int	BufLen;
 	char		Buf[256];
-	char		KeyArr[SK_PNMI_VPD_ARR_SIZE][SK_PNMI_VPD_STR_SIZE];
-	char		KeyStr[SK_PNMI_VPD_STR_SIZE];
+	char		KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+	char		KeyStr[SK_PNMI_VPD_KEY_SIZE];
 	unsigned int	KeyNo;
 	unsigned int	Offset;
 	unsigned int	Index;
@@ -3914,7 +4046,6 @@
 	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr),
 		&KeyNo);
 	if (Ret != SK_PNMI_ERR_OK) {
-
 		*pLen = 0;
 		return (Ret);
 	}
@@ -3939,7 +4070,6 @@
 			for (Index = 0; Index < KeyNo; Index ++) {
 
 				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
-
 					FirstIndex = Index;
 					LastIndex = Index+1;
 					break;
@@ -4352,7 +4482,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -4369,7 +4499,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int		Ret;
 	unsigned int	Index;
@@ -4419,7 +4550,7 @@
 		}
 
 #else /* SK_NDIS_64BIT_CTR */
-		
+
 		/*
 		 * for compatibility, at least 32bit are required for oid
 		 */
@@ -4431,7 +4562,7 @@
 			*pLen = sizeof(SK_U64);
 			return (SK_PNMI_ERR_TOO_SHORT);
 		}
-		
+
 		Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
 #endif /* SK_NDIS_64BIT_CTR */
 		break;
@@ -4529,32 +4660,30 @@
 		case OID_SKGE_IN_ERRORS_CTS:
 		case OID_GEN_RCV_ERROR:
 			Val64RxHwErrs =
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW)+
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH)+
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG)-
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_LONGFRAMES)+
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT);
-			break;
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex)-
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_LONGFRAMES, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
+	        break;
 
 		case OID_SKGE_TX_HW_ERROR_CTS:
 		case OID_SKGE_OUT_ERROR_CTS:
 		case OID_GEN_XMIT_ERROR:
 			Val64TxHwErrs =
-				GetStatVal(pAC, IoC, 0,
-				SK_PNMI_HTX_EXCESS_COL) +
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL)+
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN)+
-				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER)+
-				GetStatVal(pAC, IoC, 0,
-				SK_PNMI_HTX_EXCESS_COL);
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex);
 			break;
 		}
 	}
@@ -4766,61 +4895,142 @@
 		break;
 
 	case OID_SKGE_TX_SW_QUEUE_LEN:
-		Val64 = pAC->Pnmi.TxSwQueueLen;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+		}
+		/* Single net mode */
+		else {
+			Val64 =  pAC->Pnmi.Port[0].TxSwQueueLen +
+				pAC->Pnmi.Port[1].TxSwQueueLen;
+		}			
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
+
 	case OID_SKGE_TX_SW_QUEUE_MAX:
-		Val64 = pAC->Pnmi.TxSwQueueMax;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
+				pAC->Pnmi.Port[1].TxSwQueueMax;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_TX_RETRY:
-		Val64 = pAC->Pnmi.TxRetryCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].TxRetryCts +
+				pAC->Pnmi.Port[1].TxRetryCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_RX_INTR_CTS:
-		Val64 = pAC->Pnmi.RxIntrCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].RxIntrCts +
+				pAC->Pnmi.Port[1].RxIntrCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_TX_INTR_CTS:
-		Val64 = pAC->Pnmi.TxIntrCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].TxIntrCts +
+				pAC->Pnmi.Port[1].TxIntrCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_RX_NO_BUF_CTS:
-		Val64 = pAC->Pnmi.RxNoBufCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
+				pAC->Pnmi.Port[1].RxNoBufCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_TX_NO_BUF_CTS:
-		Val64 = pAC->Pnmi.TxNoBufCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
+				pAC->Pnmi.Port[1].TxNoBufCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_TX_USED_DESCR_NO:
-		Val64 = pAC->Pnmi.TxUsedDescrNo;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
+				pAC->Pnmi.Port[1].TxUsedDescrNo;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_RX_DELIVERED_CTS:
-		Val64 = pAC->Pnmi.RxDeliveredCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
+				pAC->Pnmi.Port[1].RxDeliveredCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_RX_OCTETS_DELIV_CTS:
-		Val64 = pAC->Pnmi.RxOctetsDeliveredCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
+				pAC->Pnmi.Port[1].RxOctetsDeliveredCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
@@ -4836,19 +5046,45 @@
 		break;
 
 	case OID_SKGE_IN_ERRORS_CTS:
-		Val64 = Val64RxHwErrs + pAC->Pnmi.RxNoBufCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = Val64RxHwErrs + 
+				pAC->Pnmi.Port[0].RxNoBufCts +
+				pAC->Pnmi.Port[1].RxNoBufCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_OUT_ERROR_CTS:
-		Val64 = Val64TxHwErrs + pAC->Pnmi.TxNoBufCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = Val64TxHwErrs + 
+				pAC->Pnmi.Port[0].TxNoBufCts +
+				pAC->Pnmi.Port[1].TxNoBufCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
 
 	case OID_SKGE_ERR_RECOVERY_CTS:
-		Val64 = pAC->Pnmi.ErrRecoveryCts;
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
+		}
+		/* Single net mode */
+		else {
+			Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
+				pAC->Pnmi.Port[1].ErrRecoveryCts;
+		}
 		SK_PNMI_STORE_U64(pBuf, Val64);
 		*pLen = sizeof(SK_U64);
 		break;
@@ -4867,13 +5103,12 @@
 		break;
 
 	case OID_GEN_RCV_ERROR:
-		Val64 = Val64RxHwErrs + pAC->Pnmi.RxNoBufCts;
+		Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
 
 		/*
 		 * by default 32bit values are evaluated
 		 */
 		if (!Is64BitReq) {
-			SK_U32	Val32;
 			Val32 = (SK_U32)Val64;
 			SK_PNMI_STORE_U32(pBuf, Val32);
 			*pLen = sizeof(SK_U32);
@@ -4885,13 +5120,12 @@
 		break;
 
 	case OID_GEN_XMIT_ERROR:
-		Val64 = Val64TxHwErrs + pAC->Pnmi.TxNoBufCts;
+		Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
 
 		/*
 		 * by default 32bit values are evaluated
 		 */
 		if (!Is64BitReq) {
-			SK_U32	Val32;
 			Val32 = (SK_U32)Val64;
 			SK_PNMI_STORE_U32(pBuf, Val32);
 			*pLen = sizeof(SK_U32);
@@ -4903,13 +5137,12 @@
 		break;
 
 	case OID_GEN_RCV_NO_BUFFER:
-		Val64 = pAC->Pnmi.RxNoBufCts;
+		Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
 
 		/*
 		 * by default 32bit values are evaluated
 		 */
 		if (!Is64BitReq) {
-			SK_U32	Val32;
 			Val32 = (SK_U32)Val64;
 			SK_PNMI_STORE_U32(pBuf, Val32);
 			*pLen = sizeof(SK_U32);
@@ -4921,7 +5154,7 @@
 		break;
 
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
-		Val32 = (SK_U32)pAC->Pnmi.TxSwQueueLen;
+		Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
 		SK_PNMI_STORE_U32(pBuf, Val32);
 		*pLen = sizeof(SK_U32);
 		break;
@@ -4956,7 +5189,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -4976,7 +5209,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	int		Ret;
 	unsigned int	PhysPortIndex;
@@ -5049,7 +5283,7 @@
 		 * statistic always up to date some time. Then we can
 		 * remove this type of call.
 		 */
-		if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+		if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
 
 			*pLen = 0;
 			return (Ret);
@@ -5062,7 +5296,7 @@
 		switch (Id) {
 
 		case OID_SKGE_RLMT_MODE:
-			*pBuf = (char)pAC->Rlmt.RlmtMode;
+			*pBuf = (char)pAC->Rlmt.Net[0].RlmtMode;
 			*pLen = sizeof(char);
 			break;
 
@@ -5088,8 +5322,7 @@
 
 				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
 
-					*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(
-						PhysPortIndex);
+					*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex);
 					break;
 				}
 			}
@@ -5097,8 +5330,7 @@
 			break;
 
 		case OID_SKGE_RLMT_PORT_PREFERRED:
-			*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(
-				pAC->Rlmt.MacPreferred);
+			*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference);
 			*pLen = sizeof(char);
 			break;
 
@@ -5165,6 +5397,7 @@
 			/* Send an event to RLMT to change the mode */
 			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
 			EventParam.Para32[0] |= (SK_U32)(*pBuf);
+			EventParam.Para32[1] = 0;
 			if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
 				EventParam) > 0) {
 
@@ -5204,6 +5437,7 @@
 			 */
 			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
 			EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
+			EventParam.Para32[1] = NetIndex;
 			if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
 				EventParam) > 0) {
 
@@ -5264,7 +5498,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -5281,7 +5515,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	PhysPortMax;
 	unsigned int	PhysPortIndex;
@@ -5291,26 +5526,40 @@
 	SK_U32		Val32;
 	SK_U64		Val64;
 
-
 	/*
 	 * Calculate the port indexes from the instance
 	 */
 	PhysPortMax = pAC->GIni.GIMacsFound;
 
 	if ((Instance != (SK_U32)(-1))) {
-
+		/* Check instance range */
 		if ((Instance < 1) || (Instance > PhysPortMax)) {
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_UNKNOWN_INST);
 		}
 
+		/* Single net mode */
 		PhysPortIndex = Instance - 1;
+
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			PhysPortIndex = NetIndex;
+		}
+
+		/* Both net modes */
 		Limit = PhysPortIndex + 1;
 	}
 	else {
+		/* Single net mode */
 		PhysPortIndex = 0;
 		Limit = PhysPortMax;
+
+		/* Dual net mode */
+		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+			PhysPortIndex = NetIndex;
+			Limit = PhysPortIndex + 1;
+		}
 	}
 
 	/*
@@ -5360,7 +5609,7 @@
 	 * Update statistic and increment semaphores to indicate that
 	 * an update was already done.
 	 */
-	if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
 
 		*pLen = 0;
 		return (Ret);
@@ -5449,7 +5698,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -5469,7 +5718,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	PhysPortMax;
 	unsigned int	PhysPortIndex;
@@ -5480,6 +5730,7 @@
 	char		Val8;
 	int		Ret;
 	SK_EVPARA	EventParam;
+	SK_U32		Val32;
 
 
 	/*
@@ -5489,18 +5740,23 @@
 	PhysPortMax = pAC->GIni.GIMacsFound;
 	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
 
-	if ((Instance != (SK_U32)(-1))) {
+	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */
+		LogPortMax--;
+	}
 
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
 		if ((Instance < 1) || (Instance > LogPortMax)) {
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_UNKNOWN_INST);
 		}
-
 		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
 		Limit = LogPortIndex + 1;
 	}
-	else {
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
 		LogPortIndex = 0;
 		Limit = LogPortMax;
 	}
@@ -5535,10 +5791,17 @@
 			}
 			break;
 
+        case OID_SKGE_MTU:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
 				SK_PNMI_ERR041MSG);
-
 			*pLen = 0;
 			return (SK_PNMI_ERR_GENERAL);
 		}
@@ -5755,6 +6018,12 @@
 				Offset += sizeof(char);
 				break;
 
+			case OID_SKGE_MTU:
+				Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
+				SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+				Offset += sizeof(SK_U32);
+				break;
+
 			default:
 				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR042,
 					SK_PNMI_ERR042MSG);
@@ -5790,7 +6059,20 @@
 		}
 		break;
 
-	default:
+	case OID_SKGE_MTU:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != sizeof(SK_U32)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+    default:
 		*pLen = 0;
 		return (SK_PNMI_ERR_READ_ONLY);
 	}
@@ -5812,7 +6094,8 @@
 				break;
 			}
 			if (Val8 < SK_LMODE_HALF ||
-				Val8 > SK_LMODE_AUTOSENSE) {
+				(LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) ||
+				(LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) {
 
 				*pLen = 0;
 				return (SK_PNMI_ERR_BAD_VALUE);
@@ -5887,7 +6170,8 @@
 				break;
 			}
 			if (Val8 < SK_FLOW_MODE_NONE ||
-				Val8 > SK_FLOW_MODE_SYM_OR_REM) {
+				(LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) ||
+				(LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) {
 
 				*pLen = 0;
 				return (SK_PNMI_ERR_BAD_VALUE);
@@ -5963,7 +6247,8 @@
 				break;
 			}
 			if (Val8 < SK_MS_MODE_AUTO ||
-				Val8 > SK_MS_MODE_SLAVE) {
+				(LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) ||
+				(LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) {
 
 				*pLen = 0;
 				return (SK_PNMI_ERR_BAD_VALUE);
@@ -6026,10 +6311,35 @@
 					return (SK_PNMI_ERR_GENERAL);
 				}
 			}
-			
+
 			Offset += sizeof(char);
 			break;
 
+		case OID_SKGE_MTU :
+			/* Check the value range */
+			Val32 = *(SK_U32*)(pBuf + Offset);
+			if (Val32 == 0) {
+				/* mtu of this port remains unchanged */
+				Offset += sizeof(SK_U32);
+				break;
+			}
+			if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			Offset += sizeof(SK_U32);
+			break;
+
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR045,
 				SK_PNMI_ERR045MSG);
@@ -6052,7 +6362,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -6072,7 +6382,8 @@
 char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
 unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
 SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
-unsigned int TableIndex) /* Index to the Id table */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	Index;
 	unsigned int	Limit;
@@ -6502,7 +6813,7 @@
  *
  * Description:
  *	The COMMON module only tells us if the mode is half or full duplex.
- *	But in the decade of auto sensing it is useful for the user to
+ *	But in the decade of auto sensing it is usefull for the user to
  *	know if the mode was negotiated or forced. Therefore we have a
  *	look to the mode, which was last used by the negotiation process.
  *
@@ -6566,8 +6877,8 @@
 unsigned int KeyArrLen,	/* Length of array in bytes */
 unsigned int *pKeyNo)	/* Number of keys */
 {
-	unsigned int		BufKeysLen = 128;
-	char			BufKeys[128];
+	unsigned int		BufKeysLen = SK_PNMI_VPD_BUFSIZE;
+	char			BufKeys[SK_PNMI_VPD_BUFSIZE];
 	unsigned int		StartOffset;
 	unsigned int		Offset;
 	int			Index;
@@ -6598,12 +6909,12 @@
 	 * errorlog notification. This case should not happen because
 	 * the maximum number of keys is limited due to RAM limitations
 	 */
-	if (*pKeyNo > SK_PNMI_VPD_ARR_SIZE) {
+	if (*pKeyNo > SK_PNMI_VPD_ENTRIES) {
 
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
 			SK_PNMI_ERR015MSG);
 
-		*pKeyNo = SK_PNMI_VPD_ARR_SIZE;
+		*pKeyNo = SK_PNMI_VPD_ENTRIES;
 	}
 
 	/*
@@ -6618,15 +6929,15 @@
 			continue;
 		}
 
-		if (Offset - StartOffset > SK_PNMI_VPD_STR_SIZE) {
+		if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) {
 
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
 				SK_PNMI_ERR016MSG);
 			return (SK_PNMI_ERR_GENERAL);
 		}
 
-		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_STR_SIZE,
-			&BufKeys[StartOffset], SK_PNMI_VPD_STR_SIZE);
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
 
 		Index ++;
 		StartOffset = Offset + 1;
@@ -6635,8 +6946,8 @@
 	/* Last key not zero terminated? Get it anyway */
 	if (StartOffset < Offset) {
 
-		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_STR_SIZE,
-			&BufKeys[StartOffset], SK_PNMI_VPD_STR_SIZE);
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
 	}
 
 	return (SK_PNMI_ERR_OK);
@@ -6698,7 +7009,8 @@
 
 static int RlmtUpdate(
 SK_AC *pAC,	/* Pointer to adapter context */
-SK_IOC IoC)	/* IO context handle */
+SK_IOC IoC,	/* IO context handle */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	SK_EVPARA	EventParam;
 
@@ -6711,6 +7023,8 @@
 
 	/* Send an synchronuous update event to the module */
 	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
 	if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {
 
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
@@ -6764,7 +7078,7 @@
 
 		/*
 		 * It is an auto-clearing register. If the command bits
-		 * went to zero again, the statistics are transferred.
+		 * went to zero again, the statistics are transfered.
 		 * Normally the command should be executed immediately.
 		 * But just to be sure we execute a loop.
 		 */
@@ -6807,40 +7121,49 @@
  */
 
 static SK_U64 GetStatVal(
-SK_AC *pAC,			/* Pointer to adapter context */
-SK_IOC IoC,			/* IO context handle */
+SK_AC *pAC,					/* Pointer to adapter context */
+SK_IOC IoC,					/* IO context handle */
 unsigned int LogPortIndex,	/* Index of the logical Port to be processed */
-unsigned int StatIndex)		/* Index to statistic value */
+unsigned int StatIndex,		/* Index to statistic value */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
 {
 	unsigned int	PhysPortIndex;
 	unsigned int	PhysPortMax;
 	SK_U64		Val = 0;
 
 
-	if (LogPortIndex == 0) {
+	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){	/* Dual net mode */
 
-		PhysPortMax = pAC->GIni.GIMacsFound;
+		PhysPortIndex = NetIndex;
+		Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+    }	/* end of dual net mode */
 
-		/* Add counter of all active ports */
-		for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
-			PhysPortIndex ++) {
+	else { /* single net mode */
 
-			if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+		if (LogPortIndex == 0) {
 
-				Val += GetPhysStatVal(pAC, IoC, PhysPortIndex,
-					StatIndex);
-			}
-		}
+			PhysPortMax = pAC->GIni.GIMacsFound;
 
-		/* Correct value because of port switches */
-		Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
-	}
-	else {
-		/* Get counter value of physical port */
-		PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
-		Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
-	}
+			/* Add counter of all active ports */
+			for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+				PhysPortIndex ++) {
+
+				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+					Val += GetPhysStatVal(pAC, IoC, PhysPortIndex,
+						StatIndex);
+				}
+			}
 
+			/* Correct value because of port switches */
+			Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
+		}
+		else {
+			/* Get counter value of physical port */
+			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+		}
+	} /* end of single net mode */
 	return (Val);
 }
 
@@ -6862,8 +7185,8 @@
  */
 
 static SK_U64 GetPhysStatVal(
-SK_AC *pAC,			/* Pointer to adapter context */
-SK_IOC IoC,			/* IO context handle */
+SK_AC *pAC,					/* Pointer to adapter context */
+SK_IOC IoC,					/* IO context handle */
 unsigned int PhysPortIndex,	/* Index of the logical Port to be processed */
 unsigned int StatIndex)		/* Index to statistic value */
 {
@@ -6959,7 +7282,8 @@
 
 static void ResetCounter(
 SK_AC *pAC,		/* Pointer to adapter context */
-SK_IOC IoC)		/* IO context handle */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 NetIndex)
 {
 	unsigned int	PhysPortIndex;
 	SK_EVPARA	EventParam;
@@ -6971,7 +7295,10 @@
 	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);
 
 	/* Notify RLMT module */
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
 	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
+	EventParam.Para32[1] = 0;
 
 	/* Notify SIRQ module */
 	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);
@@ -7019,16 +7346,16 @@
 		sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
 	pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
 	pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
-	pAC->Pnmi.TxSwQueueMax = 0;
-	pAC->Pnmi.TxRetryCts = 0;
-	pAC->Pnmi.RxIntrCts = 0;
-	pAC->Pnmi.TxIntrCts = 0;
-	pAC->Pnmi.RxNoBufCts = 0;
-	pAC->Pnmi.TxNoBufCts = 0;
-	pAC->Pnmi.TxUsedDescrNo = 0;
-	pAC->Pnmi.RxDeliveredCts = 0;
-	pAC->Pnmi.RxOctetsDeliveredCts = 0;
-	pAC->Pnmi.ErrRecoveryCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0;
+	pAC->Pnmi.Port[NetIndex].TxRetryCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxIntrCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxIntrCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0;
+	pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0;
+	pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0;
 }
 
 /*****************************************************************************
@@ -7037,7 +7364,7 @@
  *
  * Description:
  *	The trap buffer stores various events. A user application somehow
- *	gets notified that an event occurred and retrieves the trap buffer
+ *	gets notified that an event occured and retrieves the trap buffer
  *	contens (or simply polls the buffer). The buffer is organized as
  *	a ring which stores the newest traps at the beginning. The oldest
  *	traps are overwritten by the newest ones. Each trap entry has a
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgesirq.c linux/drivers/net/sk98lin/skgesirq.c
--- v2.4.6/linux/drivers/net/sk98lin/skgesirq.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/skgesirq.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skgesirq.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.55 $
- * Date:	$Date: 2000/06/19 08:36:25 $
+ * Version:	$Revision: 1.65 $
+ * Date:	$Date: 2001/02/23 13:41:51 $
  * Purpose:	Special IRQ module
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2000 SysKonnect 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
@@ -27,6 +26,37 @@
  * History:
  *
  *	$Log: skgesirq.c,v $
+ *	Revision 1.65  2001/02/23 13:41:51  gklug
+ *	fix: PHYS2INST should be used correctly for Dual Net operation
+ *	chg: do no longer work with older PNMI
+ *	
+ *	Revision 1.64  2001/02/15 11:27:04  rassmann
+ *	Working with RLMT v1 if SK_MAX_NETS undefined.
+ *	
+ *	Revision 1.63  2001/02/06 10:44:23  mkunz
+ *	- NetIndex added to interface functions of pnmi V4 with dual net support
+ *	
+ *	Revision 1.62  2001/01/31 15:31:41  gklug
+ *	fix: problem with autosensing an SR8800 switch
+ *	
+ *	Revision 1.61  2000/11/09 11:30:09  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *
+ *	Revision 1.60  2000/10/18 12:37:48  cgoos
+ *	Reinserted the comment for version 1.56.
+ *	
+ *	Revision 1.59  2000/10/18 12:22:20  cgoos
+ *	Added workaround for half duplex hangup.
+ *	
+ *	Revision 1.58  2000/09/28 13:06:04  gklug
+ *	fix: BCOM may NOT be touched if XMAC is in RESET state
+ *	
+ *	Revision 1.57  2000/09/08 12:38:39  cgoos
+ *	Added forgotten variable declaration.
+ *	
+ *	Revision 1.56  2000/09/08 08:12:13  cgoos
+ *	Changed handling of parity errors in SkGeHwErr (correct reset of error).
+ *
  *	Revision 1.55  2000/06/19 08:36:25  cgoos
  *	Changed comment.
  *	
@@ -216,39 +246,38 @@
  *
  ******************************************************************************/
 
-
 /*
-	Special Interrupt handler
-
-	The following abstract should show how this module is included
-	in the driver path:
-
-	In the ISR of the driver the bits for frame transmission complete and
-	for receive complete are checked and handled by the driver itself.
-	The bits of the slow path mask are checked after this and then the
-	entry into the so-called "slow path" is prepared. It is an implemetors
-	decision whether this is executed directly or just scheduled by
-	disabling the mask. In the interrupt service routine events may be
-	generated, so it would be a good idea to call the EventDispatcher
-	right after this ISR.
-
-	The Interrupt service register of the adapter is NOT read by this
-	module. SO if the drivers implemetor needs a while loop around the
-	slow data paths Interrupt bits, he needs to call the SkGeIsr() for
-	each loop entered.
-
-	However, the XMAC Interrupt status registers are read in a while loop.
-
-*/
+ *	Special Interrupt handler
+ *
+ *	The following abstract should show how this module is included
+ *	in the driver path:
+ *
+ *	In the ISR of the driver the bits for frame transmission complete and
+ *	for receive complete are checked and handled by the driver itself.
+ *	The bits of the slow path mask are checked after this and then the
+ *	entry into the so-called "slow path" is prepared. It is an implemetors
+ *	decision whether this is executed directly or just scheduled by
+ *	disabling the mask. In the interrupt service routine events may be
+ *	generated, so it would be a good idea to call the EventDispatcher
+ *	right after this ISR.
+ *
+ *	The Interrupt service register of the adapter is NOT read by this
+ *	module. SO if the drivers implemetor needs a while loop around the
+ *	slow data paths Interrupt bits, he needs to call the SkGeIsr() for
+ *	each loop entered.
+ *
+ *	However, the XMAC Interrupt status registers are read in a while loop.
+ *
+ */
+ 
 static const char SysKonnectFileId[] =
-	"$Id: skgesirq.c,v 1.55 2000/06/19 08:36:25 cgoos Exp $" ;
+	"$Id: skgesirq.c,v 1.65 2001/02/23 13:41:51 gklug Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skgepnmi.h"		/* PNMI Definitions */
 #include "h/skrlmt.h"		/* RLMT Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
 
-
 /* local function prototypes */
 static int	SkGePortCheckUpXmac(SK_AC*, SK_IOC, int);
 static int	SkGePortCheckUpBcom(SK_AC*, SK_IOC, int);
@@ -257,21 +286,31 @@
 static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
 static void	SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
 
+/*
+ * Define an array of RX counter which are checked
+ * in AutoSense mode to check whether a link is not able to autonegotiate.
+ */
+static const SK_U32 SkGeRxOids[]= {
+	OID_SKGE_STAT_RX_64,
+	OID_SKGE_STAT_RX_127,
+	OID_SKGE_STAT_RX_255,
+	OID_SKGE_STAT_RX_511,
+	OID_SKGE_STAT_RX_1023,
+	OID_SKGE_STAT_RX_MAX,
+} ;
 
 #ifdef __C2MAN__
 /*
-	Special IRQ function
-
-	General Description:
-
+ *	Special IRQ function
+ *
+ *	General Description:
+ *
  */
 intro()
 {}
 #endif
 
-/*
- * Define return codes of SkGePortCheckUp and CheckShort
- */
+/* Define return codes of SkGePortCheckUp and CheckShort. */
 #define	SK_HW_PS_NONE		0	/* No action needed */
 #define	SK_HW_PS_RESTART	1	/* Restart needed */
 #define	SK_HW_PS_LINK		2	/* Link Up actions needed */
@@ -287,13 +326,13 @@
  *
  */
 void	SkHWInitDefSense(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
 int	Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
 
-	pPrt = &pAC->GIni.GP[Port] ;
+	pPrt = &pAC->GIni.GP[Port];
 
 	pPrt->PAutoNegTimeOut = 0;
 
@@ -302,15 +341,16 @@
 		return;
 	}
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 		("AutoSensing: First mode %d on Port %d\n",
-		(int) SK_LMODE_AUTOFULL,
+		(int)SK_LMODE_AUTOFULL,
 		 Port));
 
 	pPrt->PLinkMode = SK_LMODE_AUTOFULL;
 
 	return;
-}
+}	/* SkHWInitDefSense */
+
 
 /******************************************************************************
  *
@@ -323,29 +363,30 @@
  *
  */
 SK_U8	SkHWSenseGetNext(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
 int	Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
 
-	pPrt = &pAC->GIni.GP[Port] ;
+	pPrt = &pAC->GIni.GP[Port];
 
 	pPrt->PAutoNegTimeOut = 0;
 
 	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
 		/* Leave all as configured */
-		return(pPrt->PLinkModeConf);
+		return (pPrt->PLinkModeConf);
 	}
 
 	if (pPrt->PLinkMode == SK_LMODE_AUTOFULL) {
 		/* Return next mode AUTOBOTH */
-		return(SK_LMODE_AUTOBOTH);
+		return (SK_LMODE_AUTOBOTH);
 	}
 
 	/* Return default autofull */
-	return(SK_LMODE_AUTOFULL);
-}
+	return (SK_LMODE_AUTOFULL);
+}	/* SkHWSenseGetNext */
+
 
 /******************************************************************************
  *
@@ -360,12 +401,12 @@
 void	SkHWSenseSetNext(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int	Port,			/* Port Index (MAC_1 + n) */
 SK_U8	NewMode)	/* New Mode to be written in sense mode */
 {
 	SK_GEPORT	*pPrt;
 
-	pPrt = &pAC->GIni.GP[Port] ;
+	pPrt = &pAC->GIni.GP[Port];
 
 	pPrt->PAutoNegTimeOut = 0;
 
@@ -373,13 +414,13 @@
 		return;
 	}
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
-		("AutoSensing: next mode %d on Port %d\n", (int) NewMode,
-		 Port));
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("AutoSensing: next mode %d on Port %d\n", (int)NewMode, Port));
 	pPrt->PLinkMode = NewMode;
 
 	return;
-}
+}	/* SkHWSenseSetNext */
+
 
 /******************************************************************************
  *
@@ -394,47 +435,44 @@
 void	SkHWLinkDown(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
 	SK_U16		Word;
 
-	pPrt = &pAC->GIni.GP[Port] ;
+	pPrt = &pAC->GIni.GP[Port];
 
-	/* Disable all XMAC interrupts */
+	/* Disable all XMAC interrupts. */
 	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
 
-	/* Disable Receive and Transmitter */
+	/* Disable Receiver and Transmitter. */
 	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
-	XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX|XM_MMU_ENA_TX));
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
 	
-	/* disable all PHY interrupts */
-	switch (pAC->GIni.GP[Port].PhyType) {
+	/* Disable all PHY interrupts. */
+	switch (pPrt->PhyType) {
 		case SK_PHY_BCOM:
-			/* make sure that PHY is initialized */
+			/* Make sure that PHY is initialized. */
 			if (pAC->GIni.GP[Port].PState) {
-				/* Workaround BCOM Errata (#10523) all BCom */
-				/* Disable Power Management if link is down */
-				PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL,
-					&Word);
-				PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL,	
+				/* NOT allowed if BCOM is in RESET state */
+				/* Workaround BCOM Errata (#10523) all BCom. */
+				/* Disable Power Management if link is down. */
+				PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Word);
+				PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL,
 					Word | PHY_B_AC_DIS_PM);
+				PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 0xffff);
 			}
-			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
-				0xffff);
 			break;
 		case SK_PHY_LONE:
-			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
-				0x0);
+			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 0x0);
 			break;
 		case SK_PHY_NAT:
 			/* todo: National
-			PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
-				0xffff); */
+			PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 0xffff); */
 			break;
 	}
 
-	/* Init default sense mode */
+	/* Init default sense mode. */
 	SkHWInitDefSense(pAC, IoC, Port);
 
 	if (!pPrt->PHWLinkUp) {
@@ -444,27 +482,25 @@
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
 		("Link down Port %d\n", Port));
 
-	/* Set Link to DOWN */
+	/* Set Link to DOWN. */
 	pPrt->PHWLinkUp = SK_FALSE;
 
 	/* Reset Port stati */
 	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
-	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE ;
+	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 
 	/*
-	 * Reinit Phy especially when the AutoSense default is set now
+	 * Reinit Phy especially when the AutoSense default is set now.
 	 */
 	SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
 
-	/*
-	 * GP0: used for workaround of Rev. C
-	 * Errata 2
-	 */
+	/* GP0: used for workaround of Rev. C Errata 2. */
+
+	/* Do NOT signal to RLMT. */
 
-	/* Do NOT signal to RLMT */
+	/* Do NOT start the timer here. */
+}	/* SkHWLinkDown */
 
-	/* Do NOT start the timer here */
-}
 
 /******************************************************************************
  *
@@ -477,21 +513,21 @@
  *
  */
 void	SkHWLinkUp(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
 int	Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
 
-	pPrt = &pAC->GIni.GP[Port] ;
+	pPrt = &pAC->GIni.GP[Port];
 
 	if (pPrt->PHWLinkUp) {
 		/* We do NOT need to proceed on active link */
 		return;
 	} 
 
-	pPrt->PHWLinkUp = SK_TRUE ;
-	pPrt->PAutoNegFail = SK_FALSE ;
+	pPrt->PHWLinkUp = SK_TRUE;
+	pPrt->PAutoNegFail = SK_FALSE;
 	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
 
 	if (pPrt->PLinkMode != SK_LMODE_AUTOHALF &&
@@ -504,17 +540,19 @@
 		/* Set Link Mode */
 		if (pPrt->PLinkMode == SK_LMODE_FULL) {
 			pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL;
-		} else {
+		}
+		else {
 			pPrt->PLinkModeStatus = SK_LMODE_STAT_HALF;
 		}
 
 		/* No flow control without autonegotiation */
-		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE ;
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 
 		/* RX/TX enable */
 		SkXmRxTxEnable(pAC, IoC, Port);
 	}
-}
+}	/* SkHWLinkUp */
+
 
 /******************************************************************************
  *
@@ -522,27 +560,28 @@
  *
  */
 static	void	SkMacParity(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
 int	Port)		/* Port Index of the port failed */
 {
 	SK_EVPARA	Para;
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	SK_U64		TxMax;		/* TxMax Counter */
-	unsigned int	Len;
+	unsigned	Len;
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Clear IRQ */
-	SK_OUT16(IoC, MR_ADDR(Port,TX_MFF_CTRL1), MFF_CLR_PERR) ;
+	SK_OUT16(IoC, MR_ADDR(Port,TX_MFF_CTRL1), MFF_CLR_PERR);
 
 	if (pPrt->PCheckPar) {
 		if (Port == MAC_1) {
 			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E016,
-				SKERR_SIRQ_E016MSG) ;
-		} else {
+				SKERR_SIRQ_E016MSG);
+		}
+		else {
 			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E017,
-				SKERR_SIRQ_E017MSG) ;
+				SKERR_SIRQ_E017MSG);
 		}
 		Para.Para64 = Port;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
@@ -552,17 +591,18 @@
 		return;
 	}
 
-
 	/* Check whether frames with a size of 1k were sent */
 	Len = sizeof(SK_U64);
-	SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_MAX, (char *) &TxMax,
-		&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+	SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_MAX, (char *)&TxMax,
+		&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+		pAC->Rlmt.Port[Port].Net->NetNumber);
 
 	if (TxMax > 0) {
 		/* From now on check the parity */
 		pPrt->PCheckPar = SK_TRUE;
 	}
-}
+}	/* SkMacParity */
+
 
 /******************************************************************************
  *
@@ -578,17 +618,22 @@
 SK_U32	HwStatus)	/* Interrupt status word */
 {
 	SK_EVPARA	Para;
+	SK_U16		Word;
 
-	if (HwStatus & IS_IRQ_STAT) {
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E013,
-			SKERR_SIRQ_E013MSG) ;
-		Para.Para64 = 0;
-		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
-	}
+	if ((HwStatus & IS_IRQ_MST_ERR) || (HwStatus & IS_IRQ_STAT)) {
+		if (HwStatus & IS_IRQ_STAT) {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG);
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG);
+		}
+
+		/* Reset all bits in the PCI STATUS register */
+		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+		SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+		SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
+		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
-	if (HwStatus & IS_IRQ_MST_ERR) {
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E012,
-			SKERR_SIRQ_E012MSG) ;
 		Para.Para64 = 0;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
 	}
@@ -596,57 +641,54 @@
 	if (HwStatus & IS_NO_STAT_M1) {
 		/* Ignore it */
 		/* This situation is also indicated in the descriptor */
-		SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INSTAT) ;
+		SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INSTAT);
 	}
 
 	if (HwStatus & IS_NO_STAT_M2) {
 		/* Ignore it */
 		/* This situation is also indicated in the descriptor */
-		SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INSTAT) ;
+		SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INSTAT);
 	}
 
 	if (HwStatus & IS_NO_TIST_M1) {
 		/* Ignore it */
 		/* This situation is also indicated in the descriptor */
-		SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INTIST) ;
+		SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INTIST);
 	}
 
 	if (HwStatus & IS_NO_TIST_M2) {
 		/* Ignore it */
 		/* This situation is also indicated in the descriptor */
-		SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INTIST) ;
+		SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INTIST);
 	}
 
 	if (HwStatus & IS_RAM_RD_PAR) {
-		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR) ;
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E014,
-			SKERR_SIRQ_E014MSG) ;
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
 		Para.Para64 = 0;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
 	}
 
 	if (HwStatus & IS_RAM_WR_PAR) {
-		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR) ;
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E015,
-			SKERR_SIRQ_E015MSG) ;
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
 		Para.Para64 = 0;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
 	}
 
 	if (HwStatus & IS_M1_PAR_ERR) {
-		SkMacParity(pAC, IoC, MAC_1) ;
+		SkMacParity(pAC, IoC, MAC_1);
 	}
 
 	if (HwStatus & IS_M2_PAR_ERR) {
-		SkMacParity(pAC, IoC, MAC_2) ;
+		SkMacParity(pAC, IoC, MAC_2);
 	}
 
 	if (HwStatus & IS_R1_PAR_ERR) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P) ;
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P);
 
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E018,
-			SKERR_SIRQ_E018MSG) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG);
 		Para.Para64 = MAC_1;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_1;
@@ -655,17 +697,16 @@
 
 	if (HwStatus & IS_R2_PAR_ERR) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P) ;
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P);
 
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E019,
-			SKERR_SIRQ_E019MSG) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG);
 		Para.Para64 = MAC_2;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_2;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
+}	/* SkGeHwErr */
 
-}
 
 /******************************************************************************
  *
@@ -680,13 +721,13 @@
 SK_IOC	IoC,		/* IO context */
 SK_U32	Istatus)	/* Interrupt status word */
 {
-	SK_U32		RegVal32;	/* Read register Value */
 	SK_EVPARA	Para;
+	SK_U32		RegVal32;	/* Read register Value */
 	SK_U16		XmIsr;
 
 	if (Istatus & IS_HW_ERR) {
-		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32) ;
-		SkGeHwErr(pAC, IoC, RegVal32) ;
+		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+		SkGeHwErr(pAC, IoC, RegVal32);
 	}
 
 	/*
@@ -694,41 +735,101 @@
 	 */
 	/* Check whether XMACs are correctly initialized */
 	if ((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) &&
-	    !pAC->GIni.GP[MAC_1].PState) {
-		/* XMAC was not initialized but Packet timeout occurred */
+		!pAC->GIni.GP[MAC_1].PState) {
+		/* XMAC was not initialized but Packet timeout occured */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
-			SKERR_SIRQ_E004MSG) ;
+			SKERR_SIRQ_E004MSG);
 	}
 
 	if ((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) &&
 	    !pAC->GIni.GP[MAC_2].PState) {
-		/* XMAC was not initialized but Packet timeout occurred */
+		/* XMAC was not initialized but Packet timeout occured */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
-			SKERR_SIRQ_E005MSG) ;
+			SKERR_SIRQ_E005MSG);
 	}
 
 	if (Istatus & IS_PA_TO_RX1) {
 		/* Means network is filling us up */
 		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
-			SKERR_SIRQ_E002MSG) ;
-		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1) ;
+			SKERR_SIRQ_E002MSG);
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1);
 	}
 
 	if (Istatus & IS_PA_TO_RX2) {
 		/* Means network is filling us up */
 		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
-			SKERR_SIRQ_E003MSG) ;
-		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2) ;
+			SKERR_SIRQ_E003MSG);
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2);
 	}
 
 	if (Istatus & IS_PA_TO_TX1) {
+		unsigned int	Len;
+		SK_U64		Octets;
+		SK_GEPORT	*pPrt = &pAC->GIni.GP[0];
+
 		/* May be a normal situation in a server with a slow network */
-		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1) ;
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+		/*
+		 * workaround: if in half duplex mode, check for tx hangup.
+		 * Read number of TX'ed bytes, wait for 10 ms, then compare
+		 * the number with current value. If nothing changed, we
+		 * assume that tx is hanging and do a FIFO flush (see event
+		 * routine).
+		 */
+		if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || 
+		    pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+		    !pPrt->HalfDupTimerActive) {
+			/* 
+			 * many more pack. arb. timeouts may come in between,
+			 * we ignore those
+			 */
+			pPrt->HalfDupTimerActive = SK_TRUE;
+
+			Len = sizeof(SK_U64);
+			SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *) &Octets,
+				&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 0),
+				pAC->Rlmt.Port[0].Net->NetNumber);
+			pPrt->LastOctets = Octets;
+			Para.Para32[0] = 0;
+			SkTimerStart(pAC, IoC,
+				&pPrt->HalfDupChkTimer,
+				SK_HALFDUP_CHK_TIME,
+				SKGE_HWAC,
+				SK_HWEV_HALFDUP_CHK,
+				Para);
+		}
 	}
 
 	if (Istatus & IS_PA_TO_TX2) {
+		unsigned int	Len;
+		SK_U64		Octets;
+		SK_GEPORT	*pPrt = &pAC->GIni.GP[1];
+
 		/* May be a normal situation in a server with a slow network */
-		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2) ;
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2);
+
+		/*
+		 * workaround: see above
+		 */
+		if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || 
+		    pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+		    !pPrt->HalfDupTimerActive) {
+			pPrt->HalfDupTimerActive = SK_TRUE;
+
+			Len = sizeof(SK_U64);
+			SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *) &Octets,
+				&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 1),
+				pAC->Rlmt.Port[1].Net->NetNumber);
+			pPrt->LastOctets = Octets;
+			Para.Para32[0] = 1;
+			SkTimerStart(pAC, IoC,
+				&pPrt->HalfDupChkTimer,
+				SK_HALFDUP_CHK_TIME,
+				SKGE_HWAC,
+				SK_HWEV_HALFDUP_CHK,
+				Para);
+		}
 	}
 
 	/*
@@ -736,9 +837,9 @@
 	 */
 	if (Istatus & IS_R1_C) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C) ;
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
-			SKERR_SIRQ_E006MSG) ;
+			SKERR_SIRQ_E006MSG);
 		Para.Para64 = MAC_1;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_1;
@@ -747,9 +848,9 @@
 
 	if (Istatus & IS_R2_C) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C) ;
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
-			SKERR_SIRQ_E007MSG) ;
+			SKERR_SIRQ_E007MSG);
 		Para.Para64 = MAC_2;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_2;
@@ -758,9 +859,9 @@
 
 	if (Istatus & IS_XS1_C) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C) ;
+		SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
-			SKERR_SIRQ_E008MSG) ;
+			SKERR_SIRQ_E008MSG);
 		Para.Para64 = MAC_1;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_1;
@@ -769,9 +870,9 @@
 
 	if (Istatus & IS_XA1_C) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C) ;
+		SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
-			SKERR_SIRQ_E009MSG) ;
+			SKERR_SIRQ_E009MSG);
 		Para.Para64 = MAC_1;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_1;
@@ -780,9 +881,9 @@
 
 	if (Istatus & IS_XS2_C) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C) ;
+		SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
-			SKERR_SIRQ_E010MSG) ;
+			SKERR_SIRQ_E010MSG);
 		Para.Para64 = MAC_2;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_2;
@@ -791,9 +892,9 @@
 
 	if (Istatus & IS_XA2_C) {
 		/* Clear IRQ */
-		SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C) ;
+		SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
-			SKERR_SIRQ_E011MSG) ;
+			SKERR_SIRQ_E011MSG);
 		Para.Para64 = MAC_2;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
 		Para.Para32[0] = MAC_2;
@@ -801,52 +902,59 @@
 	}
 
 	/*
-	 * external reg interrupt
+	 * External reg interrupt.
 	 */
 	if (Istatus & IS_EXT_REG) {
 		SK_U16 	PhyInt;
 		SK_U16 	PhyIMsk;
-		int	i;
-		/* test IRQs from PHY */
-		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-			switch (pAC->GIni.GP[i].PhyType) {
+		int		i;
+		SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+		/* Test IRQs from PHY. */
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+			pPrt = &pAC->GIni.GP[i];
+			switch (pPrt->PhyType) {
 			case SK_PHY_XMAC:
 				break;
 			case SK_PHY_BCOM:
-	    			if(pAC->GIni.GP[i].PState) {
-					PHY_READ(IoC, &pAC->GIni.GP[i], i,
-						PHY_BCOM_INT_STAT, &PhyInt);
-					PHY_READ(IoC, &pAC->GIni.GP[i], i,
-						PHY_BCOM_INT_MASK, &PhyIMsk);
+				if (pPrt->PState) {
+					PHY_READ(IoC, pPrt, i, PHY_BCOM_INT_STAT, &PhyInt);
+					PHY_READ(IoC, pPrt, i, PHY_BCOM_INT_MASK, &PhyIMsk);
+
+#ifdef xDEBUG
+					if (PhyInt & PhyIMsk) {
+						CMSMPrintString(
+							pAC->pConfigTable,
+							MSG_TYPE_RUNTIME_INFO,
+							"SirqIsr - Stat: %x",
+							(void *)PhyInt,
+							(void *)NULL);
+					}
+#endif	/* DEBUG */
 					
-					if (PhyInt & (~PhyIMsk)) {
-						SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+					if (PhyInt & ~PhyIMsk) {
+						SK_DBG_MSG(
+							pAC,
+							SK_DBGMOD_HWM,
 							SK_DBGCAT_IRQ,
-							("Port %d Bcom Int: %x "
-							" Mask: %x\n",
-							i, PhyInt, PhyIMsk));
-						SkPhyIsrBcom(pAC, IoC, i,
-							(SK_U16) 
-							(PhyInt & (~PhyIMsk)));
+							("Port %d Bcom Int: %x Mask: %x\n",
+								i, PhyInt, PhyIMsk));
+						SkPhyIsrBcom(pAC, IoC, i, PhyInt);
 					}
 				}
-				else {
-				}
 				break;
 			case SK_PHY_LONE:
-				PHY_READ(IoC, &pAC->GIni.GP[i], i,
-					PHY_LONE_INT_STAT, &PhyInt);
-				PHY_READ(IoC, &pAC->GIni.GP[i], i,
-					PHY_LONE_INT_ENAB, &PhyIMsk);
+				PHY_READ(IoC, pPrt, i, PHY_LONE_INT_STAT, &PhyInt);
+				PHY_READ(IoC, pPrt, i, PHY_LONE_INT_ENAB, &PhyIMsk);
 				
 				if (PhyInt & PhyIMsk) {
-					SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+					SK_DBG_MSG(
+						pAC,
+						SK_DBGMOD_HWM,
 						SK_DBGCAT_IRQ,
-						("Port %d  Lone Int: %x "
-						" Mask: %x\n",
+						("Port %d  Lone Int: %x Mask: %x\n",
 						i, PhyInt, PhyIMsk));
-					SkPhyIsrLone(pAC, IoC, i,
-						(SK_U16) (PhyInt & PhyIMsk));
+					SkPhyIsrLone(pAC, IoC, i, PhyInt);
 				}
 				break;
 			case SK_PHY_NAT:
@@ -869,12 +977,12 @@
 		 * us only a link going down.
 		 */
 		/* clear interrupt */
-		SK_OUT8(IoC, MR_ADDR(MAC_1,LNK_SYNC_CTRL), LED_CLR_IRQ);
+		SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ);
 	}
 
 	/* Check MAC after link sync counter */
 	if (Istatus & IS_MAC1) {
-		XM_IN16(IoC, MAC_1, XM_ISRC, &XmIsr) ;
+		XM_IN16(IoC, MAC_1, XM_ISRC, &XmIsr);
 		SkXmIrq(pAC, IoC, MAC_1, XmIsr);
 	}
 
@@ -889,7 +997,7 @@
 
 	/* Check MAC after link sync counter */
 	if (Istatus & IS_MAC2) {
-		XM_IN16(IoC, MAC_2, XM_ISRC, &XmIsr) ;
+		XM_IN16(IoC, MAC_2, XM_ISRC, &XmIsr);
 		SkXmIrq(pAC, IoC, MAC_2, XmIsr);
 	}
 
@@ -900,20 +1008,9 @@
 	if (Istatus & IS_TIMINT) {
 		SkHwtIsr(pAC, IoC);
 	}
-}
+}	/* SkGeSirqIsr */
+
 
-/*
- * Define an array of RX counter which are checked
- * in AutoSense mode to check whether a link is not able to autonegotiate.
- */
-static const SK_U32 SkGeRxOids[]= {
-	OID_SKGE_STAT_RX_64,
-	OID_SKGE_STAT_RX_127,
-	OID_SKGE_STAT_RX_255,
-	OID_SKGE_STAT_RX_511,
-	OID_SKGE_STAT_RX_1023,
-	OID_SKGE_STAT_RX_MAX,
-} ;
 /******************************************************************************
  *
  * SkGePortCheckShorts - Implementing of the Workaround Errata # 2
@@ -923,19 +1020,19 @@
  *	1	Restart needed on this port
  */
 int	SkGePortCheckShorts(
-SK_AC	*pAC,		/* Adapters context */
+SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int	Port)		/* Which port should be checked */
+int		Port)		/* Which port should be checked */
 {
-	SK_U64		Shorts;		/* Short Event Counter */
+	SK_U64		Shorts;			/* Short Event Counter */
 	SK_U64		CheckShorts;	/* Check value for Short Event Counter */
-	SK_U64		RxCts;		/* RX Counter (packets on network) */
-	SK_U64		RxTmp;		/* RX temp. Counter */
-	SK_U64		FcsErrCts;	/* FCS Error Counter */
-	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	unsigned int	Len;
-	int		Rtv;		/* Return value */
-	int		i;
+	SK_U64		RxCts;			/* RX Counter (packets on network) */
+	SK_U64		RxTmp;			/* RX temp. Counter */
+	SK_U64		FcsErrCts;		/* FCS Error Counter */
+	SK_GEPORT	*pPrt;			/* GIni Port struct pointer */
+	unsigned 	Len;
+	int			Rtv;			/* Return value */
+	int			i;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -946,8 +1043,9 @@
 	 * Extra precaution: check for short Event counter
 	 */
 	Len = sizeof(SK_U64);
-	SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *) &Shorts,
-		&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+	SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *)&Shorts,
+		&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+		pAC->Rlmt.Port[Port].Net->NetNumber);
 
 	/*
 	 * Read RX counter (packets seen on the network and not neccesarily
@@ -956,9 +1054,10 @@
 	Len = sizeof(SK_U64);
 	RxCts = 0;
 
-	for (i = 0; i < sizeof(SkGeRxOids)/sizeof(SK_U32) ; i++) {
-		SkPnmiGetVar(pAC, IoC, SkGeRxOids[i], (char *) &RxTmp,
-			&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+	for (i = 0; i < sizeof(SkGeRxOids)/sizeof(SK_U32); i++) {
+		SkPnmiGetVar(pAC, IoC, SkGeRxOids[i], (char *)&RxTmp,
+			&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+			pAC->Rlmt.Port[Port].Net->NetNumber);
 		RxCts += RxTmp;
 	}
 
@@ -973,19 +1072,20 @@
 		 * Reset Link Restart counter
 		 */
 		pPrt->PLinkResCt = 0;
+		pPrt->PAutoNegTOCt = 0;
 
 		/* If link is up check for 2 */
 		CheckShorts = 2;
 
 		Len = sizeof(SK_U64);
 		SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_FCS,
-			(char *) &FcsErrCts, &Len,
-			(SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+			(char *)&FcsErrCts, &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+			pAC->Rlmt.Port[Port].Net->NetNumber);
 		
 		if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 		    pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
 		    (pPrt->PLinkMode == SK_LMODE_HALF ||
-		     pPrt->PLinkMode == SK_LMODE_FULL)) {
+			 pPrt->PLinkMode == SK_LMODE_FULL)) {
 			/*
 			 * This is autosensing and we are in the fallback
 			 * manual full/half duplex mode.
@@ -997,8 +1097,9 @@
 				 */
 				pPrt->PPrevFcs = FcsErrCts;
 				pPrt->PPrevShorts = Shorts;
-				return(SK_HW_PS_RESTART);
-			} else {
+				return (SK_HW_PS_RESTART);
+			}
+			else {
 				pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
 			}
 		}
@@ -1006,20 +1107,18 @@
 		if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
 		    (!(FcsErrCts - pPrt->PPrevFcs))) {
 			/*
-			 * Note: The compare with zero above has to be done
-			 * the way shown, otherwise the Linux driver will
-			 * have a problem.
+			 * Note: The compare with zero above has to be done the way shown,
+			 * otherwise the Linux driver will have a problem.
 			 */
 			/*
-			 * we received a bunch of frames or no
-			 * CRC error occurred on the network ->
-			 * ok.
+			 * We received a bunch of frames or no CRC error occured on the
+			 * network -> ok.
 			 */
 			pPrt->PPrevRx = RxCts;
 			pPrt->PPrevFcs = FcsErrCts;
 			pPrt->PPrevShorts = Shorts;
 
-			return(SK_HW_PS_NONE) ;
+			return (SK_HW_PS_NONE);
 		}
 
 		pPrt->PPrevFcs = FcsErrCts;
@@ -1027,7 +1126,7 @@
 
 
 	if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 			("Short Event Count Restart Port %d \n", Port));
 		Rtv = SK_HW_PS_RESTART;
 	}
@@ -1035,13 +1134,13 @@
 	pPrt->PPrevShorts = Shorts;
 	pPrt->PPrevRx = RxCts;
 
-	return(Rtv);
-}
+	return (Rtv);
+}	/* SkGePortCheckShorts*/
 
 
 /******************************************************************************
  *
- * SkGePortCheckUp - Implementing of the Workaround Errata # 2
+ * SkGePortCheckUp - Implementation of the Workaround for Errata #2
  *
  * return:
  *	0	o.k. nothing needed
@@ -1049,15 +1148,11 @@
  *	2	Link came up
  */
 int	SkGePortCheckUp(
-SK_AC	*pAC,		/* Adapters context */
+SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int	Port)		/* Which port should be checked */
+int		Port)		/* Which port should be checked */
 {
-	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-
-	pPrt = &pAC->GIni.GP[Port];
-
-	switch (pPrt->PhyType) {
+	switch (pAC->GIni.GP[Port].PhyType) {
 	case SK_PHY_XMAC:
 		return (SkGePortCheckUpXmac(pAC, IoC, Port));
 	case SK_PHY_BCOM:
@@ -1067,9 +1162,8 @@
 	case SK_PHY_NAT:
 		return (SkGePortCheckUpNat(pAC, IoC, Port));
 	}
-	
-	return(SK_HW_PS_NONE) ;
-}
+	return (SK_HW_PS_NONE);
+}	/* SkGePortCheckUp */
 
 
 /******************************************************************************
@@ -1082,75 +1176,69 @@
  *	2	Link came up
  */
 static int	SkGePortCheckUpXmac(
-SK_AC	*pAC,		/* Adapters context */
+SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int	Port)		/* Which port should be checked */
+int		Port)		/* Which port should be checked */
 {
+	SK_U64		Shorts;		/* Short Event Counter */
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
-	SK_U16		Isrc;		/* Interrupt source register */
+	unsigned	Len;
+	int			Done;
 	SK_U32		GpReg;		/* General Purpose register value */
+	SK_U16		Isrc;		/* Interrupt source register */
 	SK_U16		IsrcSum;	/* Interrupt source register sum */
 	SK_U16		LpAb;		/* Link Partner Ability */
 	SK_U16		ResAb;		/* Resolved Ability */
-	SK_U64		Shorts;		/* Short Event Counter */
-	unsigned int	Len;
-	SK_U8		NextMode;	/* Next AutoSensing Mode */
 	SK_U16		ExtStat;	/* Extended Status Register */
-	int		Done;
+	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_U8		NextMode;	/* Next AutoSensing Mode */
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	if (pPrt->PHWLinkUp) {
 		if (pPrt->PhyType != SK_PHY_XMAC) {
-			return(SK_HW_PS_NONE) ;
+			return (SK_HW_PS_NONE);
 		}
 		else {
-			return(SkGePortCheckShorts(pAC, IoC, Port)) ;
+			return (SkGePortCheckShorts(pAC, IoC, Port));
 		}
 	}
 
 	IsrcSum = pPrt->PIsave;
 	pPrt->PIsave = 0;
 
-	/* Now wait for each ports link */
+	/* Now wait for each port's link. */
 	if (pPrt->PLinkMode == SK_LMODE_HALF ||
 	    pPrt->PLinkMode == SK_LMODE_FULL) {
 		AutoNeg = SK_FALSE;
-	} else {
+	}
+	else {
 		AutoNeg = SK_TRUE;
 	}
 
 	if (pPrt->PLinkBroken) {
 		/* Link was broken */
-		XM_IN32(IoC,Port,XM_GP_PORT, &GpReg) ;
+		XM_IN32(IoC,Port,XM_GP_PORT, &GpReg);
 
 		if ((GpReg & XM_GP_INP_ASS) == 0) {
 			/* The Link is in sync */
-			XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+			XM_IN16(IoC,Port,XM_ISRC, &Isrc);
 			IsrcSum |= Isrc;
 			SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
 			if ((Isrc & XM_IS_INP_ASS) == 0) {
 				/* It has been in sync since last Time */
 				/* Restart the PORT */
-	
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
-					("Link in sync Restart Port %d\n",
-					 Port));
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Link in sync Restart Port %d\n", Port));
 
-				/*
-				 * We now need to reinitialize the PrevSHorts
-				 * counter.
-				 */
+				/* We now need to reinitialize the PrevShorts counter. */
 				Len = sizeof(SK_U64);
-				SkPnmiGetVar(pAC, IoC,
-					OID_SKGE_STAT_RX_SHORTS,
-					(char *) &Shorts,
-					&Len,
-					(SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *)&Shorts,
+					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+					pAC->Rlmt.Port[Port].Net->NetNumber);
 				pPrt->PPrevShorts = Shorts;
 
-				pAC->GIni.GP[Port].PLinkBroken = SK_FALSE ;
+				pAC->GIni.GP[Port].PLinkBroken = SK_FALSE;
 
 				/*
 				 * Link Restart Workaround:
@@ -1165,61 +1253,60 @@
 				pAC->GIni.GP[Port].PLinkResCt ++;
 				pPrt->PAutoNegTimeOut = 0;
 
-				if (pAC->GIni.GP[Port].PLinkResCt <
-					SK_MAX_LRESTART) {
-					return(SK_HW_PS_RESTART) ;
+				if (pAC->GIni.GP[Port].PLinkResCt < SK_MAX_LRESTART) {
+					return (SK_HW_PS_RESTART);
 				}
 
 				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-					("Do NOT restart on Port %d %x %x\n",
-					Port, Isrc, IsrcSum));
+					("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
 				pAC->GIni.GP[Port].PLinkResCt = 0;
-			} else {
-				pPrt->PIsave = (SK_U16) (IsrcSum & (XM_IS_AND));
+			}
+			else {
+				pPrt->PIsave = (SK_U16)(IsrcSum & (XM_IS_AND));
 				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-					("Save Sync/nosync Port %d %x %x\n",
-					Port, Isrc, IsrcSum));
+					("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum));
+
 				/* Do nothing more if link is broken */
-				return(SK_HW_PS_NONE) ;
+				return (SK_HW_PS_NONE);
 			}
-		} else {
+		}
+		else {
 			/* Do nothing more if link is broken */
-			return(SK_HW_PS_NONE) ;
+			return (SK_HW_PS_NONE);
 		}
 
-	} else {
+	}
+	else {
 		/* Link was not broken, check if it is */
-		XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+		XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 		IsrcSum |= Isrc;
 		if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
-			XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+			XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 			IsrcSum |= Isrc;
 			if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
-				XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+				XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 				IsrcSum |= Isrc;
 				if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
-					pPrt->PLinkBroken = SK_TRUE ;
+					pPrt->PLinkBroken = SK_TRUE;
 					/*
 					 * Re-Init Link partner Autoneg flag
 					 */
 					pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
-					SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
-					   SK_DBGCAT_IRQ,
-					   ("Link broken Port %d\n",
-						 Port));
+					SK_DBG_MSG(pAC,SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Link broken Port %d\n", Port));
 
-					/* cable removed-> reinit Sensemode */
-					/* Init default sense mode */
+					/* Cable removed-> reinit sense mode. */
+					/* Init default sense mode. */
 					SkHWInitDefSense(pAC, IoC, Port);
 
-					return(SK_HW_PS_RESTART) ;
+					return (SK_HW_PS_RESTART);
 				}
 			}
-		} else {
+		}
+		else {
 			SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
-			if (SkGePortCheckShorts(pAC, IoC, Port) ==
-				SK_HW_PS_RESTART) {
-				return(SK_HW_PS_RESTART) ;
+			if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
+				return (SK_HW_PS_RESTART);
 			}
 		}
 	}
@@ -1228,18 +1315,15 @@
 	 * here we usually can check whether the link is in sync and
 	 * autonegotiation is done.
 	 */
-	XM_IN32(IoC,Port,XM_GP_PORT, &GpReg) ;
-	XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+	XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 	IsrcSum |= Isrc;
 
 	SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
 	if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
 		if ((GpReg & XM_GP_INP_ASS) == 0) {
-			/*
-			 * Save Autonegotiation Done interrupt only if link 
-			 * is in sync
-			 */
-			pPrt->PIsave = (SK_U16) (IsrcSum & (XM_IS_AND));
+			/* Save Autonegotiation Done interrupt only if link is in sync. */
+			pPrt->PIsave = (SK_U16)(IsrcSum & (XM_IS_AND));
 		}
 #ifdef	DEBUG
 		if (pPrt->PIsave & (XM_IS_AND)) {
@@ -1247,44 +1331,40 @@
 				("AutoNeg done rescheduled Port %d\n", Port));
 		}
 #endif
-		return(SK_HW_PS_NONE) ;
+		return (SK_HW_PS_NONE);
 	}
 
 	if (AutoNeg) {
 		if (IsrcSum & XM_IS_AND) {
-			SkHWLinkUp(pAC, IoC, Port) ;
+			SkHWLinkUp(pAC, IoC, Port);
 			Done = SkXmAutoNegDone(pAC,IoC,Port);
 			if (Done != SK_AND_OK) {
-				/* Get PHY parameters, for debugging only */
-				PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP,
-					&LpAb);
-				PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI,
-					&ResAb);
+				/* Get PHY parameters, for debuging only */
+				PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LpAb);
+				PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, &ResAb);
 				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 					("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
 					 Port, LpAb, ResAb));
 					
 				/* Try next possible mode */
 				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
-				SkHWLinkDown(pAC, IoC, Port) ;
+				SkHWLinkDown(pAC, IoC, Port);
 				if (Done == SK_AND_DUP_CAP) {
 					/* GoTo next mode */
-					SkHWSenseSetNext(pAC, IoC, Port,
-						NextMode);
+					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
 				}
 
-				return(SK_HW_PS_RESTART) ;
-
-			} else {
+				return (SK_HW_PS_RESTART);
+			}
+			else {
 				/*
-				 * Dummy Read extended status to prevent
-				 * extra link down/ups
+				 * Dummy Read extended status to prevent extra link down/ups
 				 * (clear Page Received bit if set)
 				 */
 				PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
 				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 					("AutoNeg done Port %d\n", Port));
-				return(SK_HW_PS_LINK) ;
+				return (SK_HW_PS_LINK);
 			}
 		} 
 		
@@ -1294,7 +1374,12 @@
 		pPrt->PAutoNegTimeOut ++;
 		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
 			/*
-			 * Timeout occurred.
+			 * Increase the Timeout counter.
+			 */
+			pPrt->PAutoNegTOCt ++;
+
+			/*
+			 * Timeout occured.
 			 * What do we need now?
 			 */
 			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
@@ -1304,42 +1389,57 @@
 			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
 				/*
-				 * Timeout occurred
+				 * Timeout occured
 				 * Set Link manually up.
 				 */
-				SkHWSenseSetNext(pAC, IoC, Port,
-					SK_LMODE_FULL);
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
-					SK_DBGCAT_IRQ,
-					("Set manual full duplex Port %d\n",
-					 Port));
+				SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n", Port));
+			}
+
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg == SK_LIPA_AUTO &&
+				pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) {
+				/*
+				 * This is rather complicated.
+				 * we need to check here whether the LIPA_AUTO
+				 * we saw before is false alert. We saw at one 
+				 * switch ( SR8800) that on boot time it sends
+				 * just one autoneg packet and does no further
+				 * autonegotiation.
+				 * Solution: we restart the autosensing after
+				 * a few timeouts.
+				 */
+				pPrt->PAutoNegTOCt = 0;
+				pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+				SkHWInitDefSense(pAC, IoC, Port);
 			}
 
 			/*
 			 * Do the restart
 			 */
-			return(SK_HW_PS_RESTART) ;
+			return (SK_HW_PS_RESTART);
 		}
-	} else {
+	}
+	else {
 		/*
 		 * Link is up and we don't need more.
 		 */
 #ifdef	DEBUG
 		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-				("ERROR: Lipa auto detected on port %d\n",
-				Port));
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
 		}
 #endif
 
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
 			("Link sync(GP), Port %d\n", Port));
-		SkHWLinkUp(pAC, IoC, Port) ;
-		return(SK_HW_PS_LINK) ;
+		SkHWLinkUp(pAC, IoC, Port);
+		return (SK_HW_PS_LINK);
 	}
 
-	return(SK_HW_PS_NONE) ;
-}
+	return (SK_HW_PS_NONE);
+}	/* SkGePortCheckUpXmac */
 
 
 /******************************************************************************
@@ -1352,59 +1452,216 @@
  *	2	Link came up
  */
 static int	SkGePortCheckUpBcom(
-SK_AC	*pAC,		/* Adapters context */
-SK_IOC	IoC,		/* IO Context */
-int	Port)		/* Which port should be checked */
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* IO Context */
+int		Port)	/* Which port should be checked */
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	int			Done;
 	SK_U16		Isrc;		/* Interrupt source register */
-	SK_U16		LpAb;		/* Link Partner Ability */
-	SK_U16		ExtStat;	/* Extended Status Register */
 	SK_U16		PhyStat;	/* Phy Status Register */
-	int		Done;
-	SK_U16		ResAb;
-	SK_U16		SWord;
+	SK_U16		ResAb;		/* Master/Slave resolution */
+	SK_U16		Ctrl;		/* Broadcom control flags */
+#ifdef DEBUG
+	SK_U16		LpAb;
+	SK_U16		ExtStat;
+#endif	/* DEBUG */
+	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Check for No HCD Link events (#10523) */
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &Isrc);
-	if ((Isrc & PHY_B_IS_NO_HDCL) == PHY_B_IS_NO_HDCL) {
 
-		/* Workaround BCOM Errata */
-		/* enable and disable Loopback mode if NO HCD occurs */
-		PHY_READ(IoC, pPrt, Port, PHY_BCOM_CTRL, &SWord);
-		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, SWord | PHY_CT_LOOP);
-		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, SWord & ~PHY_CT_LOOP);
+#ifdef xDEBUG
+	if ((Isrc & ~0x1800) == 0x70) {
+		SK_U32	Stat1, Stat2, Stat3;
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_INT_MASK, &Stat1);
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"CheckUp1 - Stat: %x, Mask: %x",
+			(void *)Isrc,
+			(void *)Stat1);
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_CTRL, &Stat1);
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		Stat3 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"Ctrl/Stat: %x, AN Adv/LP: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		Stat3 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		Stat3 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+	}
+#endif	/* DEBUG */
+
+	if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
+		/*
+		 * Workaround BCOM Errata:
+		 *	enable and disable loopback mode if "NO HCD" occurs.
+		 */
+		PHY_READ(IoC, pPrt, Port, PHY_BCOM_CTRL, &Ctrl);
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl | PHY_CT_LOOP);
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl & ~PHY_CT_LOOP);
 		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 			("No HCD Link event, Port %d\n", Port));
+#ifdef xDEBUG
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"No HCD link event, port %d.",
+			(void *)Port,
+			(void *)NULL);
+#endif	/* DEBUG */
 	}
 
+	/* Not obsolete: link status bit is latched to 0 and autoclearing! */
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
 
 	if (pPrt->PHWLinkUp) {
-		return(SK_HW_PS_NONE) ;
+		return (SK_HW_PS_NONE);
 	}
 
-	pPrt->PIsave = 0;
+#ifdef xDEBUG
+	{
+		SK_U32	Stat1, Stat2, Stat3;
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_INT_MASK, &Stat1);
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"CheckUp1a - Stat: %x, Mask: %x",
+			(void *)Isrc,
+			(void *)Stat1);
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_CTRL, &Stat1);
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
+		Stat1 = Stat1 << 16 | PhyStat;
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		Stat3 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"Ctrl/Stat: %x, AN Adv/LP: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		Stat3 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+		Stat2 = Stat2 << 16 | ResAb;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		Stat3 = 0;
+		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+	}
+#endif	/* DEBUG */
 
-	/* Now wait for each port's link */
-	if (pPrt->PLinkMode == SK_LMODE_HALF ||
-	    pPrt->PLinkMode == SK_LMODE_FULL) {
+	/* Now wait for each port's link. */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
 		AutoNeg = SK_FALSE;
-	} else {
+	}
+	else {
 		AutoNeg = SK_TRUE;
 	}
 
 	/*
-	 * here we usually can check whether the link is in sync and
+	 * Here we usually can check whether the link is in sync and
 	 * autonegotiation is done.
 	 */
-	XM_IN16(IoC, Port, XM_ISRC, &Isrc) ;
+#if 0
+/* RA;:;: obsolete */
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+#endif	/* 0 */
 
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
 
+#ifdef xDEBUG
+	if ((PhyStat & PHY_ST_LSYNC) >> 2 != (ExtStat & PHY_B_PES_LS) >> 8) {
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PhyStat != ExtStat: %x %x",
+			(void *)PhyStat,
+			(void *)ExtStat);
+	}
+#endif	/* DEBUG */
+
 	SkXmAutoNegLipaBcom(pAC, IoC, Port, PhyStat);
 	
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
@@ -1412,28 +1669,22 @@
 
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
 
-	if ((PhyStat & PHY_ST_LSYNC) == 0) {
-		if (ResAb & (PHY_B_1000S_MSF)) {
-			/* Error */
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-				("Master/Slave Fault port %d\n", Port));
-			pPrt->PAutoNegFail = SK_TRUE;
-			pPrt->PMSStatus = SK_MS_STAT_FAULT;
-			return (SK_AND_OTHER);
-		}
-		return (SK_HW_PS_NONE);
-	}
-	
-	if (ResAb & (PHY_B_1000S_MSF)) {
+	if (ResAb & PHY_B_1000S_MSF) {
 		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 			("Master/Slave Fault port %d\n", Port));
 		pPrt->PAutoNegFail = SK_TRUE;
 		pPrt->PMSStatus = SK_MS_STAT_FAULT;
-		return (SK_AND_OTHER);
-	} else if (ResAb & PHY_B_1000S_MSR) {
+		return (SK_HW_PS_RESTART);
+	}
+
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		return (SK_HW_PS_NONE);
+	}
+	else if (ResAb & PHY_B_1000S_MSR) {
 		pPrt->PMSStatus = SK_MS_STAT_MASTER;
-	} else {
+	}
+	else {
 		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
 	}
 	
@@ -1443,76 +1694,73 @@
 	if (AutoNeg) {
 		if (PhyStat & PHY_ST_AN_OVER) {
 			SkHWLinkUp(pAC, IoC, Port);
-			Done = SkXmAutoNegDone(pAC,IoC,Port);
+			Done = SkXmAutoNegDone(pAC, IoC, Port);
 			if (Done != SK_AND_OK) {
-				/* Get PHY parameters, for debugging only */
-				PHY_READ(IoC, pPrt, Port,
-					PHY_BCOM_AUNE_LP,
-					&LpAb);
-				PHY_READ(IoC, pPrt, Port,
-					PHY_BCOM_1000T_STAT,
-					&ExtStat);
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-					("AutoNeg FAIL Port %d (LpAb %x, "
-					"1000TStat %x)\n",
-					 Port, LpAb, ExtStat));
-				return(SK_HW_PS_RESTART) ;
-
-			} else {
-				/*
-				 * Dummy Read interrupt status to prevent
-				 * extra link down/ups
-				 */
-				PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT,
-					&ExtStat);
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+#ifdef DEBUG
+				/* Get PHY parameters, for debugging only. */
+				PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LpAb);
+				PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+					Port, LpAb, ExtStat));
+#endif	/* DEBUG */
+				return (SK_HW_PS_RESTART);
+			}
+			else {
+#ifdef xDEBUG
+				/* Dummy read ISR to prevent extra link downs/ups. */
+				PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+				if ((ExtStat & ~0x1800) != 0) {
+					CMSMPrintString(
+						pAC->pConfigTable,
+						MSG_TYPE_RUNTIME_INFO,
+						"CheckUp2 - Stat: %x",
+						(void *)ExtStat,
+						(void *)NULL);
+				}
+#endif	/* DEBUG */
+				
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 					("AutoNeg done Port %d\n", Port));
-				return(SK_HW_PS_LINK) ;
+				return (SK_HW_PS_LINK);
 			}
 		} 
-	} else {
+	}
+	else {	/* !AutoNeg */
 		/*
 		 * Link is up and we don't need more.
 		 */
 #ifdef	DEBUG
 		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-				("ERROR: Lipa auto detected on port %d\n",
-				Port));
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
 		}
 #endif
 
-#if 0
-		PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
-		if (ResAb & (PHY_B_1000S_MSF)) {
-			/* Error */
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-				("Master/Slave Fault port %d\n", Port));
-			pPrt->PAutoNegFail = SK_TRUE;
-			pPrt->PMSStatus = SK_MS_STAT_FAULT;
-			return (SK_AND_OTHER);
-		} else if (ResAb & PHY_B_1000S_MSR) {
-			pPrt->PMSStatus = SK_MS_STAT_MASTER ;
-		} else {
-			pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
-		}
-#endif	/* 0 */
-
-
-		/*
-		 * Dummy Read interrupt status to prevent
-		 * extra link down/ups
-		 */
+#ifdef xDEBUG
+		/* Dummy read ISR to prevent extra link downs/ups. */
 		PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+		if ((ExtStat & ~0x1800) != 0) {
+			CMSMPrintString(
+				pAC->pConfigTable,
+				MSG_TYPE_RUNTIME_INFO,
+				"CheckUp3 - Stat: %x",
+				(void *)ExtStat,
+				(void *)NULL);
+		}
+#endif	/* DEBUG */
 		
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 			("Link sync(GP), Port %d\n", Port));
-		SkHWLinkUp(pAC, IoC, Port) ;
-		return(SK_HW_PS_LINK) ;
+		SkHWLinkUp(pAC, IoC, Port);
+		return (SK_HW_PS_LINK);
 	}
 
-	return(SK_HW_PS_NONE) ;
-}
+	return (SK_HW_PS_NONE);
+}	/* SkGePortCheckUpBcom */
+
 
 /******************************************************************************
  *
@@ -1524,24 +1772,24 @@
  *	2	Link came up
  */
 static int	SkGePortCheckUpLone(
-SK_AC	*pAC,		/* Adapters context */
+SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int	Port)		/* Which port should be checked */
+int		Port)		/* Which port should be checked */
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	int		Done;
 	SK_U16		Isrc;		/* Interrupt source register */
 	SK_U16		LpAb;		/* Link Partner Ability */
-	SK_U8		NextMode;	/* Next AutoSensing Mode */
 	SK_U16		ExtStat;	/* Extended Status Register */
 	SK_U16		PhyStat;	/* Phy Status Register */
 	SK_U16		StatSum;
-	int		Done;
+	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_U8		NextMode;	/* Next AutoSensing Mode */
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	if (pPrt->PHWLinkUp) {
-		return(SK_HW_PS_NONE) ;
+		return (SK_HW_PS_NONE);
 	}
 
 	StatSum = pPrt->PIsave;
@@ -1551,7 +1799,8 @@
 	if (pPrt->PLinkMode == SK_LMODE_HALF ||
 	    pPrt->PLinkMode == SK_LMODE_FULL) {
 		AutoNeg = SK_FALSE;
-	} else {
+	}
+	else {
 		AutoNeg = SK_TRUE;
 	}
 
@@ -1559,7 +1808,7 @@
 	 * here we usually can check whether the link is in sync and
 	 * autonegotiation is done.
 	 */
-	XM_IN16(IoC, Port, XM_ISRC, &Isrc) ;
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 	PHY_READ(IoC, pPrt, Port, PHY_LONE_STAT, &PhyStat);
 	StatSum |= PhyStat;
 
@@ -1568,53 +1817,52 @@
 		/*
 		 * Save Autonegotiation Done bit
 		 */
-		pPrt->PIsave = (SK_U16) (StatSum & PHY_ST_AN_OVER);
+		pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER);
 #ifdef DEBUG
 		if (pPrt->PIsave & PHY_ST_AN_OVER) {
 			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 				("AutoNeg done rescheduled Port %d\n", Port));
 		}
 #endif
-		return(SK_HW_PS_NONE) ;
+		return (SK_HW_PS_NONE);
 	}
 
 	if (AutoNeg) {
 		if (StatSum & PHY_ST_AN_OVER) {
-			SkHWLinkUp(pAC, IoC, Port) ;
+			SkHWLinkUp(pAC, IoC, Port);
 			Done = SkXmAutoNegDone(pAC,IoC,Port);
 			if (Done != SK_AND_OK) {
-				/* Get PHY parameters, for debugging only */
+				/* Get PHY parameters, for debuging only */
 				PHY_READ(IoC, pPrt, Port,
 					PHY_LONE_AUNE_LP,
 					&LpAb);
 				PHY_READ(IoC, pPrt, Port,
 					PHY_LONE_1000T_STAT,
 					&ExtStat);
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
 					 Port, LpAb, ExtStat));
 					
 				/* Try next possible mode */
 				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
-				SkHWLinkDown(pAC, IoC, Port) ;
+				SkHWLinkDown(pAC, IoC, Port);
 				if (Done == SK_AND_DUP_CAP) {
 					/* GoTo next mode */
-					SkHWSenseSetNext(pAC, IoC, Port,
-						NextMode);
+					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
 				}
 
-				return(SK_HW_PS_RESTART) ;
+				return (SK_HW_PS_RESTART);
 
-			} else {
+			}
+			else {
 				/*
 				 * Dummy Read interrupt status to prevent
 				 * extra link down/ups
 				 */
-				PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT,
-					&ExtStat);
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 					("AutoNeg done Port %d\n", Port));
-				return(SK_HW_PS_LINK) ;
+				return (SK_HW_PS_LINK);
 			}
 		} 
 		
@@ -1624,7 +1872,7 @@
 		pPrt->PAutoNegTimeOut ++;
 		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
 			/*
-			 * Timeout occurred.
+			 * Timeout occured.
 			 * What do we need now?
 			 */
 			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
@@ -1634,7 +1882,7 @@
 			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
 				/*
-				 * Timeout occurred
+				 * Timeout occured
 				 * Set Link manually up.
 				 */
 				SkHWSenseSetNext(pAC, IoC, Port,
@@ -1648,17 +1896,17 @@
 			/*
 			 * Do the restart
 			 */
-			return(SK_HW_PS_RESTART) ;
+			return (SK_HW_PS_RESTART);
 		}
-	} else {
+	}
+	else {
 		/*
 		 * Link is up and we don't need more.
 		 */
 #ifdef	DEBUG
 		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-				("ERROR: Lipa auto detected on port %d\n",
-				Port));
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
 		}
 #endif
 
@@ -1668,14 +1916,14 @@
 		 */
 		PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat);
 		
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 			("Link sync(GP), Port %d\n", Port));
-		SkHWLinkUp(pAC, IoC, Port) ;
-		return(SK_HW_PS_LINK) ;
+		SkHWLinkUp(pAC, IoC, Port);
+		return (SK_HW_PS_LINK);
 	}
 
-	return(SK_HW_PS_NONE) ;
-}
+	return (SK_HW_PS_NONE);
+}	/* SkGePortCheckUpLone*/
 
 
 /******************************************************************************
@@ -1688,13 +1936,13 @@
  *	2	Link came up
  */
 static int	SkGePortCheckUpNat(
-SK_AC	*pAC,		/* Adapters context */
+SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
-int	Port)		/* Which port should be checked */
+int		Port)		/* Which port should be checked */
 {
 	/* todo: National */
-	return(SK_HW_PS_NONE) ;
-}
+	return (SK_HW_PS_NONE);
+}	/* SkGePortCheckUpNat */
 
 
 /******************************************************************************
@@ -1706,17 +1954,21 @@
  * Notes:
  */
 int	SkGeSirqEvent(
-SK_AC		*pAC,		/* Adapters context */
+SK_AC		*pAC,		/* Adapter Context */
 SK_IOC		IoC,		/* Io Context */
 SK_U32		Event,		/* Module specific Event */
 SK_EVPARA	Para)		/* Event specific Parameter */
 {
-	SK_U32	Port;
-	SK_U32	Time;
-	SK_U8	Val8 ;
-	int	PortStat;
+	SK_U64		Octets;
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_U32		Port;
+	SK_U32		Time;
+	unsigned	Len;
+	int			PortStat;
+	SK_U8		Val8;
 
 	Port = Para.Para32[0];
+	pPrt = & pAC->GIni.GP[Port];
 
 	switch (Event) {
 	case SK_HWEV_WATIM:
@@ -1725,7 +1977,7 @@
 
 		switch (PortStat) {
 		case SK_HW_PS_RESTART:
-			if (pAC->GIni.GP[Port].PHWLinkUp) {
+			if (pPrt->PHWLinkUp) {
 				/*
 				 * Set Link to down.
 				 */
@@ -1735,16 +1987,7 @@
 				 * Signal directly to RLMT to ensure correct
 				 * sequence of SWITCH and RESET event.
 				 */
-				Para.Para32[0] = (SK_U32) Port;
 				SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
-
-				/* Start workaround Errata #2 timer */
-				SkTimerStart(pAC, IoC,
-					&pAC->GIni.GP[Port].PWaTimer,
-					SK_WA_INA_TIME,
-					SKGE_HWAC,
-					SK_HWEV_WATIM,
-					Para);
 			}
 
 			/* Restart needed */
@@ -1757,39 +2000,38 @@
 			break;
 
 		}
-
+		
 		/* Start again the check Timer */
-		if (pAC->GIni.GP[Port].PHWLinkUp) {
+		if (pPrt->PHWLinkUp) {
 			Time = SK_WA_ACT_TIME;
-		} else {
+		}
+		else {
 			Time = SK_WA_INA_TIME;
 		}
 
-		/* todo: still needed for non-Xmac-PHYs ??? */
-		/* Start workaround Errata #2 timer */
-		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, Time,
-			SKGE_HWAC, SK_HWEV_WATIM, Para);
-
+		/* Todo: still needed for non-XMAC PHYs??? */
+		/* Start workaround Errata #2 timer. */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
+			Time, SKGE_HWAC, SK_HWEV_WATIM, Para);
 		break;
 
 	case SK_HWEV_PORT_START:
-		if (pAC->GIni.GP[Port].PHWLinkUp) {
+		if (pPrt->PHWLinkUp) {
 			/*
 			 * Signal directly to RLMT to ensure correct
 			 * sequence of SWITCH and RESET event.
 			 */
-			Para.Para32[0] = (SK_U32) Port;
 			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
 		}
 
-		SkHWLinkDown(pAC, IoC, Port) ;
+		SkHWLinkDown(pAC, IoC, Port);
 
 		/* Schedule Port RESET */
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
 
 		/* Start workaround Errata #2 timer */
-		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
-			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
 		break;
 
 	case SK_HWEV_PORT_STOP:
@@ -1798,13 +2040,13 @@
 			 * Signal directly to RLMT to ensure correct
 			 * sequence of SWITCH and RESET event.
 			 */
-			Para.Para32[0] = (SK_U32) Port;
 			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
 		}
+
 		/* Stop Workaround Timer */
-		SkTimerStop(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer) ;
+		SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
 
-		SkHWLinkDown(pAC, IoC, Port) ;
+		SkHWLinkDown(pAC, IoC, Port);
 		break;
 
 	case SK_HWEV_UPDATE_STAT:
@@ -1813,18 +2055,18 @@
 
 	case SK_HWEV_CLEAR_STAT:
 		/* We do NOT need to clear any statistics */
-		for (Port = 0; Port < (SK_U32) pAC->GIni.GIMacsFound; Port++) {
-			pAC->GIni.GP[Port].PPrevRx = 0;
-			pAC->GIni.GP[Port].PPrevFcs = 0;
-			pAC->GIni.GP[Port].PPrevShorts = 0;
+		for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) {
+			pPrt->PPrevRx = 0;
+			pPrt->PPrevFcs = 0;
+			pPrt->PPrevShorts = 0;
 		}
 		break;
 
 	case SK_HWEV_SET_LMODE:
-		Val8 = (SK_U8) Para.Para32[1];
-		if (pAC->GIni.GP[Port].PLinkModeConf != Val8) {
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PLinkModeConf != Val8) {
 			/* Set New link mode */
-			pAC->GIni.GP[Port].PLinkModeConf = Val8;
+			pPrt->PLinkModeConf = Val8;
 
 			/* Restart Port */
 			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
@@ -1833,10 +2075,10 @@
 		break;
 
 	case SK_HWEV_SET_FLOWMODE:
-		Val8 = (SK_U8) Para.Para32[1];
-		if (pAC->GIni.GP[Port].PFlowCtrlMode != Val8) {
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PFlowCtrlMode != Val8) {
 			/* Set New Flow Control mode */
-			pAC->GIni.GP[Port].PFlowCtrlMode = Val8;
+			pPrt->PFlowCtrlMode = Val8;
 
 			/* Restart Port */
 			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
@@ -1845,10 +2087,10 @@
 		break;
 
 	case SK_HWEV_SET_ROLE:
-		Val8 = (SK_U8) Para.Para32[1];
-		if (pAC->GIni.GP[Port].PMSMode != Val8) {
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PMSMode != Val8) {
 			/* Set New link mode */
-			pAC->GIni.GP[Port].PMSMode = Val8;
+			pPrt->PMSMode = Val8;
 
 			/* Restart Port */
 			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
@@ -1856,14 +2098,31 @@
 		}
 		break;
 
+	case SK_HWEV_HALFDUP_CHK:
+		/*
+		 * half duplex hangup workaround. See packet arbiter timeout
+		 * interrupt for description
+		 */
+		pPrt->HalfDupTimerActive = SK_FALSE;
+		if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || 
+		    pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
+			Len = sizeof(SK_U64);
+			SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
+				&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
+				pAC->Rlmt.Port[Port].Net->NetNumber);
+			if (pPrt->LastOctets == Octets) {
+				/* TX hanging, do a FIFO flush restarts it. */
+				SkXmFlushTxFifo(pAC, IoC, Port);
+			}
+		}
+		break;
 	default:
-		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001,
-			SKERR_SIRQ_E001MSG);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
 		break;
 	}
 
-	return(0) ;
-}
+	return (0);
+}	/* SkGeSirqEvent */
 
 
 /******************************************************************************
@@ -1875,17 +2134,20 @@
  * Returns: N/A
  */
 static void SkPhyIsrBcom(
-SK_AC		*pAC,		/* Adapters context */
+SK_AC		*pAC,		/* Adapter Context */
 SK_IOC		IoC,		/* Io Context */
-int		Port,		/* Port Num = PHY Num */
-SK_U16		IStatus)	/* Interrupts masked with PHY-Mask */
+int			Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupt Status */
 {
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 	SK_EVPARA	Para;
 
+	pPrt = &pAC->GIni.GP[Port];
+
 	if (IStatus & PHY_B_IS_PSE) {
-		/* incorrectable pair swap error */
+		/* Incorrectable pair swap error. */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
-			SKERR_SIRQ_E022MSG) ;
+			SKERR_SIRQ_E022MSG);
 	}
 	
 	if (IStatus & PHY_B_IS_MDXI_SC) {
@@ -1901,19 +2163,19 @@
 	}
 	
 	if (IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
+		Para.Para32[0] = (SK_U32)Port;
+
 		SkHWLinkDown(pAC, IoC, Port);
 
 		/* Signal to RLMT */
-		Para.Para32[0] = (SK_U32) Port;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 
 		/* Start workaround Errata #2 timer */
-		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
-			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer,
+			SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para);
 	}
 
 	if (IStatus & PHY_B_IS_NO_HDCL) {
-		/* not used */
 	}
 
 	if (IStatus & PHY_B_IS_NO_HDC) {
@@ -1947,8 +2209,7 @@
 	if (IStatus & PHY_B_IS_CRC_ER) {
 		/* not used */
 	}
-
-}
+}	/* SkPhyIsrBcom */
 
 
 /******************************************************************************
@@ -1960,10 +2221,10 @@
  * Returns: N/A
  */
 static void SkPhyIsrLone(
-SK_AC		*pAC,		/* Adapters context */
-SK_IOC		IoC,		/* Io Context */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* Io Context */
 int		Port,		/* Port Num = PHY Num */
-SK_U16		IStatus)	/* Interrupts masked with PHY-Mask */
+SK_U16	IStatus)	/* Interrupt Status */
 {
 	SK_EVPARA	Para;
 
@@ -1999,19 +2260,17 @@
 		SkHWLinkDown(pAC, IoC, Port);
 
 		/* Signal to RLMT */
-		Para.Para32[0] = (SK_U32) Port;
+		Para.Para32[0] = (SK_U32)Port;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 
 		/* Start workaround Errata #2 timer */
 		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
-			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+			SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para);
 	}
 
 	if (IStatus & PHY_L_IS_MDINT) {
 		/* not used */
 	}
-
-}
-
+}	/* SkPhyIsrLone */
 
 /* End of File */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/ski2c.c linux/drivers/net/sk98lin/ski2c.c
--- v2.4.6/linux/drivers/net/sk98lin/ski2c.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/ski2c.c	Wed Jul  4 11:50:39 2001
@@ -2,17 +2,16 @@
  *
  * Name:	ski2c.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.44 $
- * Date:	$Date: 2000/08/07 15:49:03 $
- * Purpose:	Funktions to access Voltage and Temperature Sensor
- *		(taken from Monalisa (taken from Concentrator))
+ * Version:	$Revision: 1.47 $
+ * Date:	$Date: 2001/04/05 11:38:09 $
+ * Purpose:	Functions to access Voltage and Temperature Sensor
+ *			(taken from Monalisa (taken from Concentrator))
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -28,12 +27,22 @@
  * History:
  *
  *	$Log: ski2c.c,v $
+ *	Revision 1.47  2001/04/05 11:38:09  rassmann
+ *	Set SenState to idle in SkI2cWaitIrq().
+ *	Changed error message in SkI2cWaitIrq().
+ *	
+ *	Revision 1.46  2001/04/02 14:03:35  rassmann
+ *	Changed pAC to IoC in SK_IN32().
+ *	
+ *	Revision 1.45  2001/03/21 12:12:49  rassmann
+ *	Resetting I2C_READY interrupt in SkI2cInit1().
+ *	
  *	Revision 1.44  2000/08/07 15:49:03  gklug
- *	fix: SK_INFAST only in NetWare driver
+ *	Fix: SK_INFAST only in NetWare driver.
  *	
  *	Revision 1.43  2000/08/03 14:28:17  rassmann
- *	- Added function to wait for I2C being ready before resetting the board.
- *	- Replaced one duplicate "out of range" message with correct one.
+ *	Added function to wait for I2C being ready before resetting the board.
+ *	Replaced one duplicate "out of range" message with correct one.
  *	
  *	Revision 1.42  1999/11/22 13:35:12  cgoos
  *	Changed license header to GPL.
@@ -180,10 +189,10 @@
 
 
 /*
-	I2C Protocol
-*/
+ *	I2C Protocol
+ */
 static const char SysKonnectFileId[] =
-	"$Id: ski2c.c,v 1.44 2000/08/07 15:49:03 gklug Exp $";
+	"$Id: ski2c.c,v 1.47 2001/04/05 11:38:09 rassmann Exp $";
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/lm80.h"
@@ -191,7 +200,7 @@
 
 #ifdef __C2MAN__
 /*
-	I2C protocol implemetation.
+	I2C protocol implementation.
 
 	General Description:
 
@@ -486,7 +495,7 @@
 {
 	int	i;
 
-	for (i=0; i<8; i++) {
+	for (i = 0; i < 8; i++) {
 		if (Byte & (1<<(7-i))) {
 			SkI2cSndBit(IoC, 1);
 		} else {
@@ -510,7 +519,7 @@
 	int	i;
 	int	Byte = 0;
 
-	for (i=0; i<8; i++) {
+	for (i = 0; i < 8; i++) {
 		Byte <<= 1;
 		Byte |= SkI2cRcvBit(IoC);
 	}
@@ -601,13 +610,14 @@
 		if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) {
 			SK_I2C_STOP(IoC);
 #ifndef SK_DIAG
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG);
 #endif	/* !SK_DIAG */
 			return;
 		}
-		SK_IN32(pAC, B0_ISRC, &IrqSrc);
+		SK_IN32(IoC, B0_ISRC, &IrqSrc);
 	} while ((IrqSrc & IS_I2C_READY) == 0);
 
+	pSen->SenState = SK_SEN_IDLE;
 	return;
 }	/* SkI2cWaitIrq */
 
@@ -662,10 +672,11 @@
 /*
  * read a sensor's value
  *
- * This function read a sensors value from the I2C sensor chip. The sensor
+ * This function reads a sensor's value from the I2C sensor chip. The sensor
  * is defined by its index into the sensors database in the struct pAC points
  * to.
- * Returns	1 if the read is completed
+ * Returns
+ *		1 if the read is completed
  *		0 if the read must be continued (I2C Bus still allocated)
  */
 int	SkI2cReadSensor(
@@ -695,7 +706,7 @@
 	pAC->I2c.DummyReads = SK_MAX_SENSORS;
 #endif
 
-	for (i=0; i < SK_MAX_SENSORS; i ++) {
+	for (i = 0; i < SK_MAX_SENSORS; i ++) {
 		switch (i) {
 		case 0:
 			pAC->I2c.SenTable[i].SenDesc = "Temperature";
@@ -875,16 +886,19 @@
 	
 #ifndef	SK_DIAG
 	pAC->I2c.DummyReads = pAC->I2c.MaxSens;
+
+	/* Clear the interrupt source */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
 #endif	/* !SK_DIAG */
 	
-	/* Now we are IO initialized */
+	/* Now we are I/O initialized */
 	pAC->I2c.InitLevel = SK_INIT_IO;
 	return(0);
 }	/* SkI2cInit1 */
 
 
 /*
- * Init level 2: Start first sensors read
+ * Init level 2: Start first sensor read.
  */
 static	int	SkI2cInit2(
 SK_AC	*pAC,	/* Adapter Context */
@@ -923,12 +937,13 @@
  * Level 0:
  *	Initialize only the data structures. Do NOT access hardware.
  * Level 1:
- *	Initialize hardware through SK_IN?OUT commands. Do NOT use interrupts.
+ *	Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts.
  * Level 2:
  *	Everything is possible. Interrupts may be used from now on.
  *
- * return:	0 = success
- *		other = error.
+ * return:
+ *	0 = success
+ *	other = error.
  */
 int	SkI2cInit(
 SK_AC	*pAC,	/* Adapter Context */
@@ -986,7 +1001,7 @@
 	SK_EVPARA	ParaLocal;
 	SK_BOOL		TooHigh;	/* Is sensor too high? */
 	SK_BOOL		TooLow;		/* Is sensor too low? */
-	SK_U64		CurrTime;	/* current Time */
+	SK_U64		CurrTime;	/* Current Time */
 	SK_BOOL		DoTrapSend;	/* We need to send a trap */
 	SK_BOOL		DoErrLog;	/* We need to log the error */
 	SK_BOOL		IsError;	/* We need to log the error */
@@ -1000,13 +1015,10 @@
 	/* Get the current time */
 	CurrTime = SkOsGetTime(pAC);
 
-	/* Set para to the most useful setting:
-	 * The current sensor.
-	 */
+	/* Set para to the most useful setting: The current sensor. */
 	ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens;
 
-	/* Check the Value against the thresholds */
-	/* First: Error Thresholds */
+	/* Check the Value against the thresholds. First: Error Thresholds */
 	TooHigh = (pSen->SenValue > pSen->SenThreErrHigh);
 	TooLow = (pSen->SenValue < pSen->SenThreErrLow);
 		
@@ -1192,11 +1204,11 @@
 SK_U32		Event,	/* Module specific Event */
 SK_EVPARA	Para)	/* Event specific Parameter */
 {
-	int		ReadComplete;
+	int			ReadComplete;
 	SK_SENSOR	*pSen;
 	SK_U32		Time;
 	SK_EVPARA	ParaLocal;
-	int		i;
+	int			i;
 
 	switch (Event) {
 	case SK_I2CEV_IRQ:
@@ -1224,16 +1236,16 @@
 		}
 		break;
 	case SK_I2CEV_CLEAR:
-		for (i=0; i < SK_MAX_SENSORS; i ++) {
+		for (i = 0; i < SK_MAX_SENSORS; i ++) {
 			pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
 			pAC->I2c.SenTable[i].SenErrCts = 0;
 			pAC->I2c.SenTable[i].SenWarnCts = 0;
 			pAC->I2c.SenTable[i].SenBegErrTS = 0;
 			pAC->I2c.SenTable[i].SenBegWarnTS = 0;
-			pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64) 0;
-			pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64) 0;
-			pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64) 0;
-			pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64) 0;
+			pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0;
 		}
 		break;
 	default:
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skproc.c linux/drivers/net/sk98lin/skproc.c
--- v2.4.6/linux/drivers/net/sk98lin/skproc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sk98lin/skproc.c	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,435 @@
+/******************************************************************************
+ *
+ * Name:    skproc.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.2.2.2 $
+ * Date:    $Date: 2001/03/15 12:50:13 $
+ * Purpose:	Funktions to display statictic data
+ *
+ ******************************************************************************/
+ 
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect 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.
+ *
+ *	Created 22-Nov-2000
+ *	Author: Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skproc.c,v $
+ *	Revision 1.2.2.2  2001/03/15 12:50:13  mlindner
+ *	fix: ProcFS owner protection
+ *	
+ *	Revision 1.2.2.1  2001/03/12 16:43:48  mlindner
+ *	chg: 2.4 requirements for procfs
+ *	
+ *	Revision 1.1  2001/01/22 14:15:31  mlindner
+ *	added ProcFs functionality
+ *	Dual Net functionality integrated
+ *	Rlmt networks added
+ *	
+ *
+ ******************************************************************************/
+
+#include <linux/proc_fs.h>
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+//#define SPECIAL	32		/* 0x */
+#define LARGE	64
+
+extern void proc_fill_inode(struct inode *inode, int fill);
+extern char * SkNumber(char * str, long long num, int base, int size, 
+				int precision ,int type);
+int proc_read(char *buffer,
+				char **buffer_location,
+				off_t offset,
+				int buffer_length,
+				int *eof,
+				void *data);
+
+static const char SK_Root_Dir_entry[] = "sk98lin";
+extern struct net_device *root_dev;
+
+
+struct proc_dir_entry pSkRootDir = { 
+	0,
+	sizeof(SK_Root_Dir_entry)-1,
+	(const char*)SK_Root_Dir_entry,
+	S_IFDIR | S_IRUGO,
+	2, 0, 0, 0, NULL,
+	NULL
+};
+
+
+/*****************************************************************************
+ *
+ * 	proc_read - print "summaries" entry 
+ *
+ * Description:
+ *  This function fills the proc entry with statistic data about 
+ *  the ethernet device.
+ *  
+ *
+ * Returns: buffer with statistic data
+ *	
+ */
+int proc_read(char *buffer,
+char **buffer_location,
+off_t offset,
+int buffer_length,
+int *eof,
+void *data)
+{
+	int len = 0;
+	int t;
+	int i;
+	DEV_NET				*pNet;
+	SK_AC				*pAC;
+	char 				test_buf[100];
+	unsigned int			Flags;		
+	unsigned int			Size;
+	struct net_device 		*next;
+	struct net_device 		*SkgeProcDev = root_dev;
+
+	SK_PNMI_STRUCT_DATA 	*pPnmiStruct;
+	SK_PNMI_STAT		*pPnmiStat;
+	struct proc_dir_entry *file = (struct proc_dir_entry*) data;
+
+	while (SkgeProcDev) {
+		pNet = (DEV_NET*) SkgeProcDev->priv;
+		pAC = pNet->pAC;
+		next = pAC->Next;
+		pPnmiStruct = &pAC->PnmiStruct;
+		/* NetIndex in GetStruct is now required, zero is only dummy */
+
+		for (t=pAC->GIni.GIMacsFound; t > 0; t--) {
+			if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1)
+				t--;
+			
+			spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+			Size = SK_PNMI_STRUCT_SIZE;
+			SkPnmiGetStruct(pAC, pAC->IoBase, 
+				pPnmiStruct, &Size, t-1);
+			spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	
+			if (strcmp(pAC->dev[t-1]->name, file->name) == 0) {
+				pPnmiStat = &pPnmiStruct->Stat[0];
+				len = sprintf(buffer, 
+					"\nDetailed statistic for device %s\n",
+					pAC->dev[t-1]->name);
+				len += sprintf(buffer + len,
+					"==================================\n");
+	
+				/* Board statistics */
+				len += sprintf(buffer + len, 
+					"\nBoard statistics\n\n");
+				len += sprintf(buffer + len,
+					"Active Port               %c\n",
+					'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
+					Net[t-1].PrefPort]->PortNumber);
+				len += sprintf(buffer + len,
+					"Preferred Port            %c\n",
+					'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
+					Net[t-1].PrefPort]->PortNumber);
+
+				len += sprintf(buffer + len,
+					"Bus speed (Mhz)           %d\n",
+					pPnmiStruct->BusSpeed);
+
+				len += sprintf(buffer + len,
+					"Bus width (Bit)           %d\n",
+					pPnmiStruct->BusWidth);
+
+				for (i=0; i < SK_MAX_SENSORS; i ++) {
+					if (strcmp(pAC->I2c.SenTable[i].SenDesc,
+							"Temperature") == 0 ) {
+						len += sprintf(buffer + len,
+							"Temperature (C)           %d.%d\n",
+							pAC->I2c.SenTable[i].SenValue / 10,
+							pAC->I2c.SenTable[i].SenValue % 10);
+						len += sprintf(buffer + len,
+							"Temperature (F)           %d.%d\n",
+							((((pAC->I2c.SenTable[i].SenValue)
+							*10)*9)/5 + 3200)/100,
+							((((pAC->I2c.SenTable[i].SenValue)
+							*10)*9)/5 + 3200) % 10);
+					} else if (strcmp(pAC->I2c.SenTable[i].SenDesc,
+							"Speed Fan") == 0 ) {
+						len += sprintf(buffer + len,
+							"Speed Fan                 %d\n",
+							pAC->I2c.SenTable[i].SenValue);
+					} else {
+						len += sprintf(buffer + len,
+							"%-20s      %d.%d\n",
+							pAC->I2c.SenTable[i].SenDesc,
+							pAC->I2c.SenTable[i].SenValue / 1000,
+							pAC->I2c.SenTable[i].SenValue % 1000);
+					}
+				}
+				
+				/*Receive statistics */
+				
+				len += sprintf(buffer + len, 
+				"\nReceive statistics\n\n");
+
+				len += sprintf(buffer + len,
+					"Received bytes            %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received packets          %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received errors           %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received dropped          %s\n",
+					SkNumber(test_buf, pPnmiStruct->RxNoBufCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received multicast        %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Received errors types\n");
+				len += sprintf(buffer + len,
+					"   length errors          %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxRuntCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   over errors            %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   crc errors             %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   frame errors           %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFramingCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   fifo errors            %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   missed errors          %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxMissedCts,
+					10, 0, -1, 0));
+				
+				/*Transmit statistics */
+				len += sprintf(buffer + len, 
+				"\nTransmit statistics\n\n");
+				
+				len += sprintf(buffer + len,
+					"Transmit bytes            %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit packets          %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxOkCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit errors           %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit dropped          %s\n",
+					SkNumber(test_buf, pPnmiStruct->TxNoBufCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmit collisions       %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
+					10,0,-1,0));
+				len += sprintf(buffer + len,
+					"Transmited errors types\n");
+				len += sprintf(buffer + len,
+					"   aborted errors         %ld\n",
+					pAC->stats.tx_aborted_errors);
+				len += sprintf(buffer + len,
+					"   carrier errors         %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   fifo errors            %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   heartbeat errors       %s\n",
+					SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
+					10, 0, -1, 0));
+				len += sprintf(buffer + len,
+					"   window errors          %ld\n",
+					pAC->stats.tx_window_errors);
+			}
+		}
+		SkgeProcDev = next;
+	}
+	if (offset >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*buffer_location = buffer + offset;
+	if (buffer_length >= len - offset) {
+		*eof = 1;
+	}
+	return (min(buffer_length, len - offset));
+}
+
+
+
+
+
+/*****************************************************************************
+ *
+ * SkDoDiv - convert 64bit number
+ *
+ * Description:
+ *	This function "converts" a long long number.
+ *
+ * Returns:
+ *	remainder of division
+ */
+static long SkDoDiv (long long Dividend, int Divisor, long long *pErg)
+{
+ long   	Rest;
+ long long 	Ergebnis;
+ long   	Akku;
+
+
+ Akku  = Dividend >> 32;
+
+ Ergebnis = ((long long) (Akku / Divisor)) << 32;
+ Rest = Akku % Divisor ;
+
+ Akku = Rest << 16;
+ Akku |= ((Dividend & 0xFFFF0000) >> 16);
+
+
+ Ergebnis += ((long long) (Akku / Divisor)) << 16;
+ Rest = Akku % Divisor ;
+
+ Akku = Rest << 16;
+ Akku |= (Dividend & 0xFFFF);
+
+ Ergebnis += (Akku / Divisor);
+ Rest = Akku % Divisor ;
+
+ *pErg = Ergebnis;
+ return (Rest);
+}
+
+
+#if 0
+#define do_div(n,base) ({ \
+long long __res; \
+__res = ((unsigned long long) n) % (unsigned) base; \
+n = ((unsigned long long) n) / (unsigned) base; \
+__res; })
+
+#endif
+
+
+/*****************************************************************************
+ *
+ * SkNumber - Print results
+ *
+ * Description:
+ *	This function converts a long long number into a string.
+ *
+ * Returns:
+ *	number as string
+ */
+char * SkNumber(char * str, long long num, int base, int size, int precision
+	,int type)
+{
+	char c,sign,tmp[66], *strorg = str;
+	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	int i;
+
+	if (type & LARGE)
+		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if (num < 0) {
+			sign = '-';
+			num = -num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[SkDoDiv(num,base, &num)];
+
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT)))
+		while(size-->0)
+			*str++ = ' ';
+	if (sign)
+		*str++ = sign;
+	if (type & SPECIAL) {
+		if (base==8)
+			*str++ = '0';
+		else if (base==16) {
+			*str++ = '0';
+			*str++ = digits[33];
+		}
+	}
+	if (!(type & LEFT))
+		while (size-- > 0)
+			*str++ = c;
+	while (i < precision--)
+		*str++ = '0';
+	while (i-- > 0)
+		*str++ = tmp[i];
+	while (size-- > 0)
+		*str++ = ' ';
+	
+	str[0] = '\0';
+	
+	return strorg;
+}
+
+
+
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skqueue.c linux/drivers/net/sk98lin/skqueue.c
--- v2.4.6/linux/drivers/net/sk98lin/skqueue.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/skqueue.c	Wed Jul  4 11:50:39 2001
@@ -1,23 +1,32 @@
 /******************************************************************************
  *
  * Name:	skqueue.c
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.15 $
- * Date:	$Date: 1999/11/22 13:36:29 $
+ * Project:	PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.14 $
+ * Date:	$Date: 1998/10/15 15:11:35 $
  * Purpose:	Management of an event queue.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1989-1998 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	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; either version 2 of the License, or
- *	(at your option) any later version.
- *
+ *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
+ *	The copyright notice above does not evidence any
+ *	actual or intended publication of such source code.
+ *
+ *	This Module contains Proprietary Information of SysKonnect
+ *	and should be treated as Confidential.
+ *
+ *	The information in this file is provided for the exclusive use of
+ *	the licensees of SysKonnect.
+ *	Such users have the right to use, modify, and incorporate this code
+ *	into products for purposes authorized by the license agreement
+ *	provided they include this notice and the associated copyright notice
+ *	with any such product.
  *	The information in this file is provided "AS IS" without warranty.
  *
  ******************************************************************************/
@@ -27,9 +36,6 @@
  * History:
  *
  *	$Log: skqueue.c,v $
- *	Revision 1.15  1999/11/22 13:36:29  cgoos
- *	Changed license header to GPL.
- *	
  *	Revision 1.14  1998/10/15 15:11:35  gklug
  *	fix: ID_sccs to SysKonnectFileId
  *	
@@ -82,7 +88,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.15 1999/11/22 13:36:29 cgoos Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.14 1998/10/15 15:11:35 gklug Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skqueue.h"		/* Queue Definitions */
@@ -147,7 +153,7 @@
  *		send command to state machine
  *	end
  *	return error reported by individual Event function
- *		0 if no error occurred.
+ *		0 if no error occured.
  */
 int	SkEventDispatcher(
 SK_AC	*pAC,	/* Adapters Context */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skrlmt.c linux/drivers/net/sk98lin/skrlmt.c
--- v2.4.6/linux/drivers/net/sk98lin/skrlmt.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skrlmt.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skrlmt.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.49 $
- * Date:	$Date: 1999/11/22 13:38:02 $
+ * Version:	$Revision: 1.61 $
+ * Date:	$Date: 2001/03/14 12:52:08 $
  * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,15 +26,53 @@
  * History:
  *
  *	$Log: skrlmt.c,v $
+ *	Revision 1.61  2001/03/14 12:52:08  rassmann
+ *	Fixed reporting of active port up/down to PNMI.
+ *	
+ *	Revision 1.60  2001/02/21 16:02:25  gklug
+ *	fix: when RLMT starts set Active Port for PNMI
+ *	
+ *	Revision 1.59  2001/02/16 14:38:19  rassmann
+ *	Initializing some pointers earlier in the init phase.
+ *	Rx Mbufs are freed if the net which they belong to is stopped.
+ *	
+ *	Revision 1.58  2001/02/14 14:06:31  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.57  2001/02/05 14:25:26  rassmann
+ *	Prepared RLMT for transparent operation.
+ *	
+ *	Revision 1.56  2001/01/30 10:29:09  rassmann
+ *	Not checking switching befor RlmtStart.
+ *	Editorial changes.
+ *	
+ *	Revision 1.55  2001/01/22 13:41:38  rassmann
+ *	Supporting two nets on dual-port adapters.
+ *	
+ *	Revision 1.54  2000/11/30 13:25:07  rassmann
+ *	Setting SK_TICK_INCR to 1 by default.
+ *	
+ *	Revision 1.53  2000/11/30 10:48:07  cgoos
+ *	Changed definition of SK_RLMT_BC_DELTA.
+ *	
+ *	Revision 1.52  2000/11/27 12:50:03  rassmann
+ *	Checking ports after receiving broadcasts.
+ *	
+ *	Revision 1.51  2000/11/17 08:58:00  rassmann
+ *	Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event.
+ *	
+ *	Revision 1.50  2000/11/09 12:24:34  rassmann
+ *	Indicating that segmentation check is not running anymore after
+ *	  SkRlmtCheckSeg().
+ *	Restarting segmentation timer after segmentation log.
+ *	Editorial changes.
+ *	
  *	Revision 1.49  1999/11/22 13:38:02  cgoos
  *	Changed license header to GPL.
  *	Added initialization to some variables to avoid compiler warnings.
  *	
  *	Revision 1.48  1999/10/04 14:01:17  rassmann
- *	Corrected reaction to reception of BPDU frames.
- *	Added parameter descriptions to "For Readme" section skrlmt.txt.
- *	Clarified usage of lookahead result *pForRlmt.
- *	Requested driver to present RLMT packets as soon as poosible.
+ *	Corrected reaction to reception of BPDU frames (#10441).
  *	
  *	Revision 1.47  1999/07/20 12:53:36  rassmann
  *	Fixed documentation errors for lookahead macros.
@@ -66,7 +103,7 @@
  *	
  *	Revision 1.40  1999/01/22 13:17:30  rassmann
  *	Informing PNMI of NET_UP.
- *	Clearing RLMT multicast addresses before first setting them.
+ *	Clearing RLMT multicast addresses before setting them for the first time.
  *	Reporting segmentation earlier, setting a "quiet time"
  *	 after a report.
  *	
@@ -218,13 +255,13 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skrlmt.c,v 1.49 1999/11/22 13:38:02 cgoos Exp $ (C) SysKonnect.";
+	"@(#) $Id: skrlmt.c,v 1.61 2001/03/14 12:52:08 rassmann Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKRLMT_C
 
 #ifdef __cplusplus
-xxxx	/* not supported yet - force error */
+#error C++ is not yet supported.
 extern "C" {
 #endif	/* cplusplus */
 
@@ -245,11 +282,13 @@
 #ifndef SK_LITTLE_ENDIAN
 /* First 32 bits */
 #define OFFS_LO32	1
+
 /* Second 32 bits */
 #define OFFS_HI32	0
 #else	/* SK_LITTLE_ENDIAN */
 /* First 32 bits */
 #define OFFS_LO32	0
+
 /* Second 32 bits */
 #define OFFS_HI32	1
 #endif	/* SK_LITTLE_ENDIAN */
@@ -258,58 +297,60 @@
 
 /* ----- Private timeout values ----- */
 
-#define SK_RLMT_MIN_TO_VAL		   125000	/* 1/8 sec. */
-#define SK_RLMT_DEF_TO_VAL		  1000000	/* 1 sec. */
+#define SK_RLMT_MIN_TO_VAL			   125000	/* 1/8 sec. */
+#define SK_RLMT_DEF_TO_VAL			  1000000	/* 1 sec. */
 #define SK_RLMT_PORTDOWN_TIM_VAL	   900000	/* another 0.9 sec. */
 #define SK_RLMT_PORTSTART_TIM_VAL	   100000	/* 0.1 sec. */
 #define SK_RLMT_PORTUP_TIM_VAL		  2500000	/* 2.5 sec. */
-#define SK_RLMT_SEG_TO_VAL		900000000	/* 15 min. */
+#define SK_RLMT_SEG_TO_VAL			900000000	/* 15 min. */
+
+/* Assume tick counter increment is 1 - may be set OS-dependent. */
+#ifndef SK_TICK_INCR
+#define SK_TICK_INCR	SK_CONSTU64(1)
+#endif	/* !defined(SK_TICK_INCR) */
 
 /*
  * Amount that a time stamp must be later to be recognized as "substantially
- * later". This is about 1/128 sec.
+ * later". This is about 1/128 sec, but above 1 tick counter increment.
  */
-
-#define SK_RLMT_BC_DELTA	((SK_TICKS_PER_SEC >> 7) + 1)
+#define SK_RLMT_BC_DELTA		(1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \
+									(SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR))
 
 /* ----- Private RLMT defaults ----- */
 
-#define SK_RLMT_DEF_PREF_PORT	0			/* "Lower" port. */
-#define SK_RLMT_DEF_MODE 	SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */
+#define SK_RLMT_DEF_PREF_PORT	0					/* "Lower" port. */
+#define SK_RLMT_DEF_MODE 		SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */
 
 /* ----- Private RLMT checking states ----- */
 
-#define SK_RLMT_RCS_SEG		1	/* RLMT Check State: check seg. */
-#define SK_RLMT_RCS_START_SEG	2	/* RLMT Check State: start check seg. */
-#define SK_RLMT_RCS_SEND_SEG	4	/* RLMT Check State: send BPDU packet */
-#define SK_RLMT_RCS_REPORT_SEG	8	/* RLMT Check State: report seg. */
+#define SK_RLMT_RCS_SEG			1		/* RLMT Check State: check seg. */
+#define SK_RLMT_RCS_START_SEG	2		/* RLMT Check State: start check seg. */
+#define SK_RLMT_RCS_SEND_SEG	4		/* RLMT Check State: send BPDU packet */
+#define SK_RLMT_RCS_REPORT_SEG	8		/* RLMT Check State: report seg. */
 
 /* ----- Private PORT checking states ----- */
 
-#define SK_RLMT_PCS_TX		1	/* Port Check State: check tx. */
-#define SK_RLMT_PCS_RX		2	/* Port Check State: check rx. */
+#define SK_RLMT_PCS_TX			1		/* Port Check State: check tx. */
+#define SK_RLMT_PCS_RX			2		/* Port Check State: check rx. */
 
 /* ----- Private PORT events ----- */
 
 /* Note: Update simulation when changing these. */
-
 #define SK_RLMT_PORTSTART_TIM	1100	/* Port start timeout. */
-#define SK_RLMT_PORTUP_TIM	1101	/* Port can now go up. */
+#define SK_RLMT_PORTUP_TIM		1101	/* Port can now go up. */
 #define SK_RLMT_PORTDOWN_RX_TIM	1102	/* Port did not receive once ... */
-#define SK_RLMT_PORTDOWN	1103	/* Port went down. */
+#define SK_RLMT_PORTDOWN		1103	/* Port went down. */
 #define SK_RLMT_PORTDOWN_TX_TIM	1104	/* Partner did not receive ... */
 
 /* ----- Private RLMT events ----- */
 
 /* Note: Update simulation when changing these. */
-
-#define SK_RLMT_TIM		2100	/* RLMT timeout. */
-#define SK_RLMT_SEG_TIM		2101	/* RLMT segmentation check timeout. */
+#define SK_RLMT_TIM				2100	/* RLMT timeout. */
+#define SK_RLMT_SEG_TIM			2101	/* RLMT segmentation check timeout. */
 
 #define TO_SHORTEN(tim)	((tim) / 2)
 
 /* Error numbers and messages. */
-
 #define SKERR_RLMT_E001		(SK_ERRBASE_RLMT + 0)
 #define SKERR_RLMT_E001_MSG	"No Packet."
 #define SKERR_RLMT_E002		(SKERR_RLMT_E001 + 1)
@@ -333,78 +374,70 @@
 #define SKERR_RLMT_E010_MSG	"Ignored illegal Preferred Port."
 
 /* LLC field values. */
-
-#define LLC_COMMAND_RESPONSE_BIT	1
-#define LLC_TEST_COMMAND		0xE3
-#define LLC_UI				0x03
+#define LLC_COMMAND_RESPONSE_BIT		1
+#define LLC_TEST_COMMAND				0xE3
+#define LLC_UI							0x03
 
 /* RLMT Packet fields. */
-
-#define	SK_RLMT_DSAP			0
-#define	SK_RLMT_SSAP			0
-#define SK_RLMT_CTRL			(LLC_TEST_COMMAND)
-#define SK_RLMT_INDICATOR0		0x53	/* S */
-#define SK_RLMT_INDICATOR1		0x4B	/* K */
-#define SK_RLMT_INDICATOR2		0x2D	/* - */
-#define SK_RLMT_INDICATOR3		0x52	/* R */
-#define SK_RLMT_INDICATOR4		0x4C	/* L */
-#define SK_RLMT_INDICATOR5		0x4D	/* M */
-#define SK_RLMT_INDICATOR6		0x54	/* T */
-#define SK_RLMT_PACKET_VERSION	0
+#define	SK_RLMT_DSAP					0
+#define	SK_RLMT_SSAP					0
+#define SK_RLMT_CTRL					(LLC_TEST_COMMAND)
+#define SK_RLMT_INDICATOR0				0x53	/* S */
+#define SK_RLMT_INDICATOR1				0x4B	/* K */
+#define SK_RLMT_INDICATOR2				0x2D	/* - */
+#define SK_RLMT_INDICATOR3				0x52	/* R */
+#define SK_RLMT_INDICATOR4				0x4C	/* L */
+#define SK_RLMT_INDICATOR5				0x4D	/* M */
+#define SK_RLMT_INDICATOR6				0x54	/* T */
+#define SK_RLMT_PACKET_VERSION			0
 
 /* RLMT SPT Flag values. */
-
-#define	SK_RLMT_SPT_FLAG_CHANGE		0x01
-#define	SK_RLMT_SPT_FLAG_CHANGE_ACK	0x80
+#define	SK_RLMT_SPT_FLAG_CHANGE			0x01
+#define	SK_RLMT_SPT_FLAG_CHANGE_ACK		0x80
 
 /* RLMT SPT Packet fields. */
-
-#define	SK_RLMT_SPT_DSAP		0x42
-#define	SK_RLMT_SPT_SSAP		0x42
-#define SK_RLMT_SPT_CTRL		(LLC_UI)
-#define	SK_RLMT_SPT_PROTOCOL_ID0	0x00
-#define	SK_RLMT_SPT_PROTOCOL_ID1	0x00
+#define	SK_RLMT_SPT_DSAP				0x42
+#define	SK_RLMT_SPT_SSAP				0x42
+#define SK_RLMT_SPT_CTRL				(LLC_UI)
+#define	SK_RLMT_SPT_PROTOCOL_ID0		0x00
+#define	SK_RLMT_SPT_PROTOCOL_ID1		0x00
 #define	SK_RLMT_SPT_PROTOCOL_VERSION_ID	0x00
-#define	SK_RLMT_SPT_BPDU_TYPE		0x00
-#define	SK_RLMT_SPT_FLAGS		0x00	/* ?? */
-#define	SK_RLMT_SPT_ROOT_ID0		0xFF	/* Lowest possible priority. */
-#define	SK_RLMT_SPT_ROOT_ID1		0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_BPDU_TYPE			0x00
+#define	SK_RLMT_SPT_FLAGS				0x00	/* ?? */
+#define	SK_RLMT_SPT_ROOT_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_ROOT_ID1			0xFF	/* Lowest possible priority. */
 
 /* Remaining 6 bytes will be the current port address. */
-
-#define	SK_RLMT_SPT_ROOT_PATH_COST0	0x00
-#define	SK_RLMT_SPT_ROOT_PATH_COST1	0x00
-#define	SK_RLMT_SPT_ROOT_PATH_COST2	0x00
-#define	SK_RLMT_SPT_ROOT_PATH_COST3	0x00
-#define	SK_RLMT_SPT_BRIDGE_ID0		0xFF	/* Lowest possible priority. */
-#define	SK_RLMT_SPT_BRIDGE_ID1		0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_ROOT_PATH_COST0		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST1		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST2		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST3		0x00
+#define	SK_RLMT_SPT_BRIDGE_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_BRIDGE_ID1			0xFF	/* Lowest possible priority. */
 
 /* Remaining 6 bytes will be the current port address. */
-
-#define	SK_RLMT_SPT_PORT_ID0		0xFF	/* Lowest possible priority. */
-#define	SK_RLMT_SPT_PORT_ID1		0xFF	/* Lowest possible priority. */
-#define	SK_RLMT_SPT_MSG_AGE0		0x00
-#define	SK_RLMT_SPT_MSG_AGE1		0x00
-#define	SK_RLMT_SPT_MAX_AGE0		0x00
-#define	SK_RLMT_SPT_MAX_AGE1		0xFF
-#define	SK_RLMT_SPT_HELLO_TIME0		0x00
-#define	SK_RLMT_SPT_HELLO_TIME1		0xFF
-#define	SK_RLMT_SPT_FWD_DELAY0		0x00
-#define	SK_RLMT_SPT_FWD_DELAY1		0x40
+#define	SK_RLMT_SPT_PORT_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_PORT_ID1			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_MSG_AGE0			0x00
+#define	SK_RLMT_SPT_MSG_AGE1			0x00
+#define	SK_RLMT_SPT_MAX_AGE0			0x00
+#define	SK_RLMT_SPT_MAX_AGE1			0xFF
+#define	SK_RLMT_SPT_HELLO_TIME0			0x00
+#define	SK_RLMT_SPT_HELLO_TIME1			0xFF
+#define	SK_RLMT_SPT_FWD_DELAY0			0x00
+#define	SK_RLMT_SPT_FWD_DELAY1			0x40
 
 /* Size defines. */
-
-#define SK_RLMT_MIN_PACKET_SIZE	34
-#define SK_RLMT_MAX_PACKET_SIZE	(SK_RLMT_MAX_TX_BUF_SIZE)
-#define SK_PACKET_DATA_LEN	(SK_RLMT_MAX_PACKET_SIZE - \
-				 SK_RLMT_MIN_PACKET_SIZE)
+#define SK_RLMT_MIN_PACKET_SIZE			34
+#define SK_RLMT_MAX_PACKET_SIZE			(SK_RLMT_MAX_TX_BUF_SIZE)
+#define SK_PACKET_DATA_LEN				(SK_RLMT_MAX_PACKET_SIZE - \
+										SK_RLMT_MIN_PACKET_SIZE)
 
 /* ----- RLMT packet types ----- */
-
-#define SK_PACKET_ANNOUNCE	1	/* Port announcement. */
-#define SK_PACKET_ALIVE		2	/* Alive packet to port. */
-#define SK_PACKET_ADDR_CHANGED	3	/* Port address changed. */
-#define SK_PACKET_CHECK_TX	4	/* Check your tx line. */
+#define SK_PACKET_ANNOUNCE				1	/* Port announcement. */
+#define SK_PACKET_ALIVE					2	/* Alive packet to port. */
+#define SK_PACKET_ADDR_CHANGED			3	/* Port address changed. */
+#define SK_PACKET_CHECK_TX				4	/* Check your tx line. */
 
 #ifdef SK_LITTLE_ENDIAN
 #define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
@@ -426,7 +459,6 @@
 /* typedefs *******************************************************************/
 
 /* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
-
 typedef struct s_RlmtPacket {
 	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
 	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
@@ -437,8 +469,8 @@
 	SK_U8	Indicator[7];
 	SK_U8	RlmtPacketType[2];
 	SK_U8	Align1[2];
-	SK_U8	Random[4];	/* Random value of requesting(!) station. */
-	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version */
+	SK_U8	Random[4];				/* Random value of requesting(!) station. */
+	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version. */
 	SK_U8	Data[SK_PACKET_DATA_LEN];
 } SK_RLMT_PACKET;
 
@@ -465,9 +497,9 @@
 
 /* global variables ***********************************************************/
 
-SK_MAC_ADDR	SkRlmtMcAddr = {{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
-SK_MAC_ADDR	BridgeMcAddr = {{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
-SK_MAC_ADDR	BcAddr = {{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}};
+SK_MAC_ADDR	SkRlmtMcAddr =	{{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
+SK_MAC_ADDR	BridgeMcAddr =	{{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
+SK_MAC_ADDR	BcAddr = 		{{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}};
 
 /* local variables ************************************************************/
 
@@ -477,10 +509,16 @@
 
 RLMT_STATIC void	SkRlmtCheckSwitch(
 	SK_AC	*pAC,
-	SK_IOC	IoC);
+	SK_IOC	IoC,
+	SK_U32	NetIdx);
 RLMT_STATIC void	SkRlmtCheckSeg(
 	SK_AC	*pAC,
-	SK_IOC	IoC);
+	SK_IOC	IoC,
+	SK_U32	NetIdx);
+RLMT_STATIC void	SkRlmtEvtSetNets(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_EVPARA	Para);
 
 /******************************************************************************
  *
@@ -506,7 +544,7 @@
  *	===========
  *
  *	Determine the adapter's random value.
- *	Set the hw registers, the "logical adapter address", the
+ *	Set the hw registers, the "logical MAC address", the
  *	RLMT multicast address, and eventually the BPDU multicast address.
  *
  * Context:
@@ -516,18 +554,15 @@
  *	Nothing.
  */
 void	SkRlmtInit(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-int	Level)	/* initialization level */
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+int		Level)	/* Initialization Level */
 {
 	SK_U32		i, j;
 	SK_U64		Random;
 	SK_EVPARA	Para;
 
-	SK_DBG_MSG(
-		pAC,
-		SK_DBGMOD_RLMT,
-		SK_DBGCAT_INIT,
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
 		("RLMT Init level %d.\n", Level))
 
 	switch (Level) {
@@ -541,68 +576,70 @@
 			pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
 			pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
 			pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
-		}
-
-		pAC->Rlmt.RlmtState = SK_RLMT_RS_INIT;
-		pAC->Rlmt.RootIdSet = SK_FALSE;
-		pAC->Rlmt.MacPreferred = 0xFFFFFFFF;	  /* Automatic. */
-		pAC->Rlmt.PrefPort = SK_RLMT_DEF_PREF_PORT;
-		pAC->Rlmt.MacActive = pAC->Rlmt.PrefPort; /* Just assuming. */
-		pAC->Rlmt.RlmtMode = SK_RLMT_DEF_MODE;
-		pAC->Rlmt.TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Port[i].PortNumber = i;
+			pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0];
+			pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i];
+		}
+
+		pAC->Rlmt.NumNets = 1;
+		for (i = 0; i < SK_MAX_NETS; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* Automatic. */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0];
+		pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1];
+#if SK_MAX_NETS > 1
+		pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1];
+#endif	/* SK_MAX_NETS > 1 */
 		break;
 
 	case SK_INIT_IO:	/* GIMacsFound first available here. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_INIT,
-			("RLMT: %d MACs were detected.\n",
-				pAC->GIni.GIMacsFound))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+			("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound))
 
-		/* Initialize HW registers? */
+		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
 
+		/* Initialize HW registers? */
 		if (pAC->GIni.GIMacsFound < 2) {
-			Para.Para32[0] = SK_RLMT_CHECK_LINK;
+			Para.Para32[0] = SK_RLMT_MODE_CLS;
+			Para.Para32[1] = 0;
 			(void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
 		}
 		break;
 
 	case SK_INIT_RUN:
+		/* Ensure RLMT is set to one net. */
+		if (pAC->Rlmt.NumNets > 1) {
+			Para.Para32[0] = 1;
+			Para.Para32[1] = -1;
+			SkRlmtEvtSetNets(pAC, IoC, Para);
+		}
+
 		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 			Random = SkOsGetTime(pAC);
 			*(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
 
 			for (j = 0; j < 4; j++) {
-				pAC->Rlmt.Port[i].Random[j] ^= pAC->Addr.Port[i
-					].CurrentMacAddress.a[SK_MAC_ADDR_LEN -
-					1 - j];
+				pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort->
+					CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j];
 			}
 
-			(void)SkAddrMcClear(
-				pAC,
-				IoC,
-				i,
-				SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+			(void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
 			
 			/* Add RLMT MC address. */
+			(void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT);
 
-			(void)SkAddrMcAdd(
-				pAC,
-				IoC,
-				i,
-				&SkRlmtMcAddr,
-				SK_ADDR_PERMANENT);
-
-			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
+			if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) {
 				/* Add BPDU MC address. */
-
-				(void)SkAddrMcAdd(
-					pAC,
-					IoC,
-					i,
-					&BridgeMcAddr,
-					SK_ADDR_PERMANENT);
+				(void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT);
 			}
 
 			(void)SkAddrMcUpdate(pAC, IoC, i);
@@ -612,9 +649,7 @@
 	default:	/* error */
 		break;
 	}
-
 	return;
-
 }	/* SkRlmtInit */
 
 
@@ -639,32 +674,33 @@
  *	Nothing
  */
 RLMT_STATIC void	SkRlmtBuildCheckChain(
-SK_AC	*pAC)	/* adapter context */
+SK_AC	*pAC,	/* Adapter Context */
+SK_U32	NetIdx)	/* Net Number */
 {
-	SK_U32	i;
-	SK_U32	NumMacsUp;
-	SK_U32	FirstMacUp=0;
-	SK_U32	PrevMacUp=0;
+	SK_U32			i;
+	SK_U32			NumMacsUp;
+	SK_RLMT_PORT *	FirstMacUp;
+	SK_RLMT_PORT *	PrevMacUp;
 
-	if (!(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			pAC->Rlmt.Port[i].PortsChecked = 0;
+	FirstMacUp	= NULL;
+	PrevMacUp	= NULL;
+	
+	if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) {
+			pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
 		}
-		return;	/* Nothing to build. */
+		return;	/* Done. */
 	}
-
-	SK_DBG_MSG(
-		pAC,
-		SK_DBGMOD_RLMT,
-		SK_DBGCAT_CTRL,
+			
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 		("SkRlmtBuildCheckChain.\n"))
 
 	NumMacsUp = 0;
 
-	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-		pAC->Rlmt.Port[i].PortsChecked = 0;
-		pAC->Rlmt.Port[i].PortsSuspect = 0;
-		pAC->Rlmt.Port[i].CheckingState &=
+	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+		pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+		pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0;
+		pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &=
 			~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
 
 		/*
@@ -673,156 +709,43 @@
 		 * 1. the next port that is not LinkDown and
 		 * 2. the next port that is not PortDown.
 		 */
-
-		if (!pAC->Rlmt.Port[i].LinkDown) {
+		if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
 			if (NumMacsUp == 0) {
-				FirstMacUp = i;
+				FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
 			}
 			else {
-				pAC->Rlmt.Port[PrevMacUp].PortCheck[
-					pAC->Rlmt.Port[
-					PrevMacUp].PortsChecked].CheckAddr =
-					pAC->Addr.Port[i].CurrentMacAddress;
-				pAC->Rlmt.Port[PrevMacUp].PortCheck[
-					pAC->Rlmt.Port[
-					PrevMacUp].PortsChecked].SuspectTx =
-					SK_FALSE;
-				pAC->Rlmt.Port[PrevMacUp].PortsChecked++;
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[
+					pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
+					pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
+				PrevMacUp->PortCheck[
+					PrevMacUp->PortsChecked].SuspectTx = SK_FALSE;
+				PrevMacUp->PortsChecked++;
 			}
-			PrevMacUp = i;
+			PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
 			NumMacsUp++;
 		}
 	}
 
 	if (NumMacsUp > 1) {
-		pAC->Rlmt.Port[PrevMacUp].PortCheck[pAC->Rlmt.Port[
-			PrevMacUp].PortsChecked].CheckAddr =
-			pAC->Addr.Port[FirstMacUp].CurrentMacAddress;
-		pAC->Rlmt.Port[PrevMacUp].PortCheck[pAC->Rlmt.Port[
-			PrevMacUp].PortsChecked].SuspectTx = SK_FALSE;
-		pAC->Rlmt.Port[PrevMacUp].PortsChecked++;
+		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr =
+			FirstMacUp->AddrPort->CurrentMacAddress;
+		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx =
+			SK_FALSE;
+		PrevMacUp->PortsChecked++;
 	}
 
 #ifdef DEBUG
-	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-                SK_DBG_MSG(
-                        pAC,
-                        SK_DBGMOD_RLMT,
-                        SK_DBGCAT_CTRL,
-                        ("Port %d checks %d other ports: %2X.\n",
-				i,
-				pAC->Rlmt.Port[i].PortsChecked,
-				pAC->Rlmt.Port[i].PortCheck[0].CheckAddr.a[5]))
+	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Port %d checks %d other ports: %2X.\n", NetIdx,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
 	}
 #endif	/* DEBUG */
 
 	return;       
 }	/* SkRlmtBuildCheckChain */
 
-#ifdef SK_RLMT_SLOW_LOOKAHEAD
-
-/******************************************************************************
- *
- *	SkRlmtLookaheadPacket - examine received packet shortly, count s-th
- *
- * Description:
- *	This routine examines each received packet fast and short and
- *	increments some counters.
- *	The received packet has to be stored virtually contiguous.
- *	This function does the following:
- *	- Increment some counters.
- *	- Ensure length is sufficient.
- *	- Ensure that destination address is physical port address,
- *	  RLMT multicast, or BPDU multicast address.
- *
- * Notes:
- *	This function is fully reentrant while the fast path is not blocked.
- *
- * Context:
- *	isr/dpr, not pageable
- *
- * Returns:
- *	SK_FALSE packet for upper layers
- *	SK_TRUE  packet for RLMT
- */
-SK_BOOL	SkRlmtLookaheadPacket(
-SK_AC		*pAC,		/* adapter context */
-SK_U32		PortIdx,	/* receiving port */
-SK_U8		*pLaPacket,	/* received packet's data */
-unsigned	PacketLength,	/* received packet's length */ /* Necessary? */
-unsigned	LaLength)	/* lookahead length */
-{
-	int	i;
-	SK_BOOL	IsBc;		/* Broadcast address? */
-	int	RxDest;		/* Receive destination? */
-	int	Offset;		/* Offset of data to present to LOOKAHEAD. */
-	int	NumBytes;	/* #Bytes to present to LOOKAHEAD. */
-	SK_RLMT_PACKET	*pRPacket;
-	SK_ADDR_PORT	*pAPort;
-
-#ifdef DEBUG
-	PacketLength = PacketLength;
-#endif	/* DEBUG */
-
-	pRPacket = (SK_RLMT_PACKET*)pLaPacket;
-	pAPort = &pAC->Addr.Port[PortIdx];
-
-#ifdef DEBUG
-	if (pLaPacket == NULL) {
-
-		/* Create error log entry. */
-
-		SK_ERR_LOG(
-			pAC,
-			SK_ERRCL_SW,
-			SKERR_RLMT_E001,
-			SKERR_RLMT_E001_MSG);
-
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_RX,
-			("SkRlmtLookaheadPacket: NULL pointer.\n"))
-
-		return (SK_FALSE);
-	}
-#endif	/* DEBUG */
-
-	/* Drivers should get IsBc from the descriptor. */
-
-	IsBc = SK_TRUE;
-	for (i = 0; IsBc && i < SK_MAC_ADDR_LEN; i++) {
-		IsBc = IsBc && (pLaPacket[i] == 0xFF);
-	}
-
-	SK_RLMT_PRE_LOOKAHEAD(
-		pAC,
-		PortIdx,
-		PacketLength,
-		IsBc,
-		&Offset,
-		&NumBytes)
-
-	if (NumBytes == 0) {
-		return (SK_FALSE);
-	}
-
-	SK_RLMT_LOOKAHEAD(
-		pAC,
-		PortIdx,
-		&pLaPacket[Offset],
-		IsBc,
-		pLaPacket[0] & 1,	/* Drivers: Get info from descriptor. */
-		&RxDest)
-
-	if (RxDest & SK_RLMT_RX_RLMT) {
-		return (SK_TRUE);
-	}
-
-	return (SK_FALSE);
-}	/* SkRlmtLookaheadPacket */
-
-#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
 
 /******************************************************************************
  *
@@ -838,20 +761,19 @@
  *	NULL or pointer to RLMT mbuf
  */
 RLMT_STATIC SK_MBUF	*SkRlmtBuildPacket(
-SK_AC		*pAC,		/* adapter context */
-SK_IOC		IoC,		/* I/O context */
-SK_U32		PortIdx,	/* sending port */
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* I/O Context */
+SK_U32		PortNumber,	/* Sending port */
 SK_U16		PacketType,	/* RLMT packet type */
-SK_MAC_ADDR	*SrcAddr,	/* source address */
-SK_MAC_ADDR	*DestAddr)	/* destination address */
+SK_MAC_ADDR	*SrcAddr,	/* Source address */
+SK_MAC_ADDR	*DestAddr)	/* Destination address */
 {
 	int		i;
 	SK_U16		Length;
 	SK_MBUF		*pMb;
 	SK_RLMT_PACKET	*pPacket;
 
-	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
-		NULL) {
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) {
 		pPacket = (SK_RLMT_PACKET*)pMb->pData;
 		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
 			pPacket->DstAddr[i] = DestAddr->a[i];
@@ -868,17 +790,14 @@
 		pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
 		pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
 
-		SK_U16_TO_NETWORK_ORDER(
-			PacketType,
-			&pPacket->RlmtPacketType[0]);
+		SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]);
 
 		for (i = 0; i < 4; i++) {
-			pPacket->Random[i] = pAC->Rlmt.Port[PortIdx].Random[i];
+			pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i];
 		}
 		
 		SK_U16_TO_NETWORK_ORDER(
-			SK_RLMT_PACKET_VERSION,
-			&pPacket->RlmtPacketVersion[0]);
+			SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]);
 
 		for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
 			pPacket->Data[i] = 0x00;
@@ -886,12 +805,12 @@
 
 		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
 		pMb->Length = Length;
-		pMb->PortIdx = PortIdx;
+		pMb->PortIdx = PortNumber;
 		Length -= 14;
 		SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
 
 		if (PacketType == SK_PACKET_ALIVE) {
-			pAC->Rlmt.Port[PortIdx].TxHelloCts++;
+			pAC->Rlmt.Port[PortNumber].TxHelloCts++;
 		}
 	}
 
@@ -913,13 +832,13 @@
  *	NULL or pointer to RLMT mbuf
  */
 RLMT_STATIC SK_MBUF	*SkRlmtBuildSpanningTreePacket(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* I/O context */
-SK_U32	PortIdx)	/* sending port */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Sending port */
 {
-	unsigned		i;
-	SK_U16			Length;
-	SK_MBUF			*pMb;
+	unsigned			i;
+	SK_U16				Length;
+	SK_MBUF				*pMb;
 	SK_SPTREE_PACKET	*pSPacket;
 
 	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
@@ -928,7 +847,7 @@
 		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
 			pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
 			pSPacket->SrcAddr[i] =
-				pAC->Addr.Port[PortIdx].CurrentMacAddress.a[i];
+				pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
 		}
 		pSPacket->DSap = SK_RLMT_SPT_DSAP;
 		pSPacket->SSap = SK_RLMT_SPT_SSAP;
@@ -949,13 +868,13 @@
 		pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
 
 		/*
-		 * Use virtual address as bridge ID and filter these packets
+		 * Use logical MAC address as bridge ID and filter these packets
 		 * on receive.
 		 */
-
 		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
 			pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
-				pAC->Addr.CurrentMacAddress.a[i];
+				pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber].
+					CurrentMacAddress.a[i];
 		}
 		pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
 		pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
@@ -970,11 +889,11 @@
 
 		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
 		pMb->Length = Length;
-		pMb->PortIdx = PortIdx;
+		pMb->PortIdx = PortNumber;
 		Length -= 14;
 		SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
 
-		pAC->Rlmt.Port[PortIdx].TxSpHelloReqCts++;
+		pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++;
 	}
 
 	return (pMb);       
@@ -996,36 +915,22 @@
  *	Nothing.
  */
 RLMT_STATIC void	SkRlmtSend(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_U32	PortIdx)
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Sending port */
 {
 	unsigned	j;
 	SK_EVPARA	Para;
 	SK_RLMT_PORT	*pRPort;
 
-	pRPort = &pAC->Rlmt.Port[PortIdx];
-	if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
-		if (pRPort->CheckingState &
-			(SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
-
-			/*
-			 * Port is suspicious. Send the RLMT packet to the
-			 * RLMT multicast address.
-			 */
-
-			if ((Para.pParaPtr = SkRlmtBuildPacket(
-				pAC,
-				IoC,
-				PortIdx,
-				SK_PACKET_ALIVE,
-				&pAC->Addr.Port[PortIdx].CurrentMacAddress,
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+	if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+		if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
+			/* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */
+			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
 				&SkRlmtMcAddr)) != NULL) {
-				SkEventQueue(
-					pAC,
-					SKGE_DRV,
-					SK_DRV_RLMT_SEND,
-					Para);
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
 			}
 		}
 		else {
@@ -1033,61 +938,33 @@
 			 * Send a directed RLMT packet to all ports that are
 			 * checked by the indicated port.
 			 */
-
 			for (j = 0; j < pRPort->PortsChecked; j++) {
-				if ((Para.pParaPtr =
-					SkRlmtBuildPacket(
-						pAC,
-						IoC,
-						PortIdx,
-						SK_PACKET_ALIVE,
-						&pAC->Addr.Port[PortIdx].CurrentMacAddress,
-						&pRPort->PortCheck[j].CheckAddr)
-						) != NULL) {
-					SkEventQueue(
-						pAC,
-						SKGE_DRV,
-						SK_DRV_RLMT_SEND,
-						Para);
+				if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+					SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+					&pRPort->PortCheck[j].CheckAddr)) != NULL) {
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
 				}
 			}
 		}
 	}
 
-	if ((pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
-		(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEND_SEG)) {
-
+	if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) {
 		/*
 		 * Send a BPDU packet to make a connected switch tell us
 		 * the correct root bridge.
 		 */
-
 		if ((Para.pParaPtr =
-			SkRlmtBuildSpanningTreePacket(
-				pAC,
-				IoC,
-				PortIdx)
-			) != NULL) {
-			
-			pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
+			SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) {
+			pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
 			pRPort->RootIdSet = SK_FALSE;
 
-			SkEventQueue(
-				pAC,
-				SKGE_DRV,
-				SK_DRV_RLMT_SEND,
-				Para);
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_TX,
-				("SkRlmtSend: BPDU Packet on Port %u.\n",
-					PortIdx))
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX,
+				("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber))
 		}
-	}
-
-	return;
-
+	}   
+	return;   
 }	/* SkRlmtSend */
 
 
@@ -1099,61 +976,51 @@
  *	This routine checks if a port who received a non-BPDU packet
  *	needs to go up or needs to be stopped going down.
  *
-* Context:
+ * Context:
  *	runtime, pageable?
  *
  * Returns:
  *	Nothing.
  */
 RLMT_STATIC void	SkRlmtPortReceives(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* I/O context */
-SK_U32	PortIdx)	/* port to check */
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	PortNumber)		/* Port to check */
 {
 	SK_RLMT_PORT	*pRPort;
-	SK_EVPARA	Para;
+	SK_EVPARA		Para;
 
-	pRPort = &pAC->Rlmt.Port[PortIdx];
+	pRPort = &pAC->Rlmt.Port[PortNumber];
 	pRPort->PortNoRx = SK_FALSE;
 
 	if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
 		!(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
-
 		/*
 		 * Port is marked down (rx), but received a non-BPDU packet.
 		 * Bring it up.
 		 */
-
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_RX,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 			("SkRlmtPacketReceive: Received on PortDown.\n"))
 
 		pRPort->PortState = SK_RLMT_PS_GOING_UP;
 		pRPort->GuTimeStamp = SkOsGetTime(pAC);
-		Para.Para32[0] = PortIdx;
-		SkTimerStart(
-			pAC,
-			IoC,
-			&pRPort->UpTimer,
-			SK_RLMT_PORTUP_TIM_VAL,
-			SKGE_RLMT,
-			SK_RLMT_PORTUP_TIM,
-			Para);
-		SkRlmtCheckSwitch(pAC, IoC);
-	}
+		Para.Para32[0] = PortNumber;
+		Para.Para32[1] = (SK_U32)-1;
+		SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+			SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para);
+		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+	}	/* PortDown && !SuspectTx */
 	else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_RX,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 			("SkRlmtPacketReceive: Stop bringing port down.\n"))
 		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
-		SkRlmtCheckSwitch(pAC, IoC);
-	}
+		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+	}	/* PortGoingDown */
 
-	pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
 	return;
 }	/* SkRlmtPortReceives */
 
@@ -1163,7 +1030,7 @@
  *	SkRlmtPacketReceive - receive a packet for closer examination
  *
  * Description:
- *	This routine examines a packet more closely than SkRlmtLookahead*().
+ *	This routine examines a packet more closely than SK_RLMT_LOOKAHEAD.
  *
  * Context:
  *	runtime, pageable?
@@ -1172,32 +1039,29 @@
  *	Nothing.
  */
 RLMT_STATIC void	SkRlmtPacketReceive(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_MBUF	*pMb)	/* received packet */
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_MBUF	*pMb)	/* Received packet */
 {
 #ifdef xDEBUG
 	extern	void DumpData(char *p, int size);
 #endif	/* DEBUG */
-	int			i;
-	unsigned		j;
-	SK_U16			PacketType;
-	SK_U32			PortIdx;
+	int					i;
+	unsigned			j;
+	SK_U16				PacketType;
+	SK_U32				PortNumber;
 	SK_ADDR_PORT		*pAPort;
 	SK_RLMT_PORT		*pRPort;
 	SK_RLMT_PACKET		*pRPacket;
 	SK_SPTREE_PACKET	*pSPacket;
-	SK_EVPARA		Para;
+	SK_EVPARA			Para;
+
+	PortNumber	= pMb->PortIdx;
+	pAPort = &pAC->Addr.Port[PortNumber];
+	pRPort = &pAC->Rlmt.Port[PortNumber];
 
-	PortIdx	= pMb->PortIdx;
-	pAPort = &pAC->Addr.Port[PortIdx];
-	pRPort = &pAC->Rlmt.Port[PortIdx];
-
-	SK_DBG_MSG(
-		pAC,
-		SK_DBGMOD_RLMT,
-		SK_DBGCAT_RX,
-		("SkRlmtPacketReceive: PortIdx == %d.\n", PortIdx))
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+		("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber))
 
 	pRPacket = (SK_RLMT_PACKET*)pMb->pData;
 	pSPacket = (SK_SPTREE_PACKET*)pRPacket;
@@ -1207,7 +1071,7 @@
 #endif	/* DEBUG */
 
 	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
-		SkRlmtPortReceives(pAC, IoC, PortIdx);
+		SkRlmtPortReceives(pAC, IoC, PortNumber);
 	}
 	
 	/* Check destination address. */
@@ -1216,15 +1080,8 @@
 		!SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
 		!SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
 
-		/*
-		 * Not sent to current MAC or registered MC address
-		 * => Trash it.
-		 */
-
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_RX,
+		/* Not sent to current MAC or registered MC address => Trash it. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 			("SkRlmtPacketReceive: Not for me.\n"))
 
 		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
@@ -1241,19 +1098,17 @@
 		 * Check for duplicate address here:
 		 * If Packet.Random != My.Random => DupAddr.
 		 */
-
 		for (i = 3; i >= 0; i--) {
-			if (pRPort->Random[i] !=
-				pRPacket->Random[i]) {
+			if (pRPort->Random[i] != pRPacket->Random[i]) {
 				break;
 			}
 		}
 
 		/*
-		 * CAUTION: Do not check for duplicate MAC
-		 * address in RLMT Alive Reply packets.
+		 * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply
+		 * packets (they have the LLC_COMMAND_RESPONSE_BIT set in
+		 * pRPacket->SSap).
 		 */
-
 		if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
 			pRPacket->Ctrl == SK_RLMT_CTRL &&
 			pRPacket->SSap == SK_RLMT_SSAP &&
@@ -1264,43 +1119,28 @@
 			pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
 			pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
 			pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_RX,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 				("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
 
 			/* Error Log entry. */
-
-			SK_ERR_LOG(
-				pAC,
-				SK_ERRCL_COMM,
-				SKERR_RLMT_E006,
-				SKERR_RLMT_E006_MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG);
 		}
 		else {
 			/* Simply trash it. */
-
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_RX,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 				("SkRlmtPacketReceive: Sent by me.\n"))
 		}
 
 		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
-
 		return;
 	}
 
 	/* Check SuspectTx entries. */
-
 	if (pRPort->PortsSuspect > 0) {
 		for (j = 0; j < pRPort->PortsChecked; j++) {
 			if (pRPort->PortCheck[j].SuspectTx &&
 				SK_ADDR_EQUAL(
-					pRPacket->SrcAddr,
-					pRPort->PortCheck[j].CheckAddr.a)) {
+					pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) {
 				pRPort->PortCheck[j].SuspectTx = SK_FALSE;
 				pRPort->PortsSuspect--;
 				break;
@@ -1309,7 +1149,6 @@
 	}
 
 	/* Determine type of packet. */
-
 	if (pRPacket->DSap == SK_RLMT_DSAP &&
 		pRPacket->Ctrl == SK_RLMT_CTRL &&
 		(pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
@@ -1322,7 +1161,6 @@
 		pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
 
 		/* It's an RLMT packet. */
-
 		PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
 			pRPacket->RlmtPacketType[1]);
 
@@ -1330,14 +1168,10 @@
 		case SK_PACKET_ANNOUNCE:	/* Not yet used. */
 #if 0
 			/* Build the check chain. */
-
 			SkRlmtBuildCheckChain(pAC);
 #endif	/* 0 */
 
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_RX,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 				("SkRlmtPacketReceive: Announce.\n"))
 
 			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
@@ -1345,221 +1179,145 @@
 
 		case SK_PACKET_ALIVE:
 			if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
-				SK_DBG_MSG(
-					pAC,
-					SK_DBGMOD_RLMT,
-					SK_DBGCAT_RX,
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 					("SkRlmtPacketReceive: Alive Reply.\n"))
 
-				/* Alive Reply Packet. */
-
-#if 0
-				pRPort->RlmtAcksPerTimeSlot++;
-#endif	/* 0 */
-
-				if (!(pAC->Addr.Port[PortIdx].PromMode &
-					SK_PROM_MODE_LLC) ||
+				if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) ||
 					SK_ADDR_EQUAL(
-						pRPacket->DstAddr,
-						pAPort->CurrentMacAddress.a)) {
-
+						pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) {
 					/* Obviously we could send something. */
-
-					if (pRPort->CheckingState &
-						SK_RLMT_PCS_TX) {
-						pRPort->CheckingState &=
-							~SK_RLMT_PCS_TX;
-						SkTimerStop(
-							pAC,
-							IoC,
-							&pRPort->DownTxTimer);
+					if (pRPort->CheckingState & SK_RLMT_PCS_TX) {
+						pRPort->CheckingState &=  ~SK_RLMT_PCS_TX;
+						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
 					}
 
-					if ((pRPort->PortState ==
-						SK_RLMT_PS_DOWN) &&
-						!(pRPort->CheckingState &
-						SK_RLMT_PCS_RX)) {
-						pRPort->PortState =
-							SK_RLMT_PS_GOING_UP;
-						pRPort->GuTimeStamp =
-							SkOsGetTime(pAC);
-
-						SkTimerStop(
-							pAC,
-							IoC,
-							&pRPort->DownTxTimer);
-
-						Para.Para32[0] = PortIdx;
-						SkTimerStart(
-							pAC,
-							IoC,
-							&pRPort->UpTimer,
-							SK_RLMT_PORTUP_TIM_VAL,
-							SKGE_RLMT,
-							SK_RLMT_PORTUP_TIM,
-							Para);
+					if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+						!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+						pRPort->PortState = SK_RLMT_PS_GOING_UP;
+						pRPort->GuTimeStamp = SkOsGetTime(pAC);
+
+						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+						Para.Para32[0] = PortNumber;
+						Para.Para32[1] = (SK_U32)-1;
+						SkTimerStart(pAC, IoC, &pRPort->UpTimer,
+							SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT,
+							SK_RLMT_PORTUP_TIM, Para);
 					}
 				}
 
 				/* Mark sending port as alive? */
-
 				SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
 			}
 			else {	/* Alive Request Packet. */
-				SK_DBG_MSG(
-					pAC,
-					SK_DBGMOD_RLMT,
-					SK_DBGCAT_RX,
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 					("SkRlmtPacketReceive: Alive Request.\n"))
 
 				pRPort->RxHelloCts++;
-#if 0
-				pRPort->RlmtChksPerTimeSlot++;
-#endif	/* 0 */
 
 				/* Answer. */
-
 				for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
-					pRPacket->DstAddr[i] =
-						pRPacket->SrcAddr[i];
-					pRPacket->SrcAddr[i] = pAC->Addr.Port[
-						PortIdx].CurrentMacAddress.a[i];
+					pRPacket->DstAddr[i] = pRPacket->SrcAddr[i];
+					pRPacket->SrcAddr[i] =
+						pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
 				}
 				pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
 
 				Para.pParaPtr = pMb;
-				SkEventQueue(
-					pAC,
-					SKGE_DRV,
-					SK_DRV_RLMT_SEND,
-					Para);
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
 			}
 			break;
 
 		case SK_PACKET_CHECK_TX:
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_RX,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 				("SkRlmtPacketReceive: Check your tx line.\n"))
 
-			/*
-			 * A port checking us requests us to check our tx line.
-			 */
-
+			/* A port checking us requests us to check our tx line. */
 			pRPort->CheckingState |= SK_RLMT_PCS_TX;
 
 			/* Start PortDownTx timer. */
-
-			Para.Para32[0] = PortIdx;
-			SkTimerStart(
-				pAC,
-				IoC,
-				&pRPort->DownTxTimer,
-				SK_RLMT_PORTDOWN_TIM_VAL,
-				SKGE_RLMT,
-				SK_RLMT_PORTDOWN_TX_TIM,
-				Para);
+			Para.Para32[0] = PortNumber;
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pRPort->DownTxTimer,
+				SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+				SK_RLMT_PORTDOWN_TX_TIM, Para);
 
 			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
 
-			if ((Para.pParaPtr = SkRlmtBuildPacket(
-				pAC,
-				IoC,
-				PortIdx,
-				SK_PACKET_ALIVE,
-				&pAC->Addr.Port[PortIdx].CurrentMacAddress,
+			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
 				&SkRlmtMcAddr)) != NULL) {
-				SkEventQueue(
-					pAC,
-					SKGE_DRV,
-					SK_DRV_RLMT_SEND,
-					Para);
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
 			}
 			break;
 
 		case SK_PACKET_ADDR_CHANGED:
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_RX,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 				("SkRlmtPacketReceive: Address Change.\n"))
 
 			/* Build the check chain. */
-
-			SkRlmtBuildCheckChain(pAC);
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
 			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
 			break;
 
 		default:
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_RX,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 				("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
 
 			/* RA;:;: ??? */
-
 			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
 		}
 	}
 	else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
 		pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
-		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) ==
-		SK_RLMT_SPT_SSAP) {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_RX,
+		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 			("SkRlmtPacketReceive: BPDU Packet.\n"))
 
 		/* Spanning Tree packet. */
-
 		pRPort->RxSpHelloCts++;
 
-		if (!SK_ADDR_EQUAL(
-			&pSPacket->RootId[2],
-			&pAC->Addr.CurrentMacAddress.a[0])) {
-
+		if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt.
+			Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) {
 			/*
 			 * Check segmentation if a new root bridge is set and
 			 * the segmentation check is not currently running.
 			 */
-
-			if (!SK_ADDR_EQUAL(
-					&pSPacket->RootId[2],
-					&pRPort->Root.Id[2]) &&
-				(pAC->Rlmt.LinksUp > 1) &&
-				(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
-				!(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEG)) {
-				pAC->Rlmt.CheckingState |=
-					SK_RLMT_RCS_START_SEG |
-					SK_RLMT_RCS_SEND_SEG;
+			if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) &&
+				(pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+				(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG)
+				!= 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+				SK_RLMT_RCS_SEG) == 0) {
+				pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+					SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
 			}
 
 			/* Store tree view of this port. */
-
 			for (i = 0; i < 8; i++) {
 				pRPort->Root.Id[i] = pSPacket->RootId[i];
 			}
 			pRPort->RootIdSet = SK_TRUE;
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+				("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+					PortNumber,
+					pRPort->Root.Id[0], pRPort->Root.Id[1],
+					pRPort->Root.Id[2], pRPort->Root.Id[3],
+					pRPort->Root.Id[4], pRPort->Root.Id[5],
+					pRPort->Root.Id[6], pRPort->Root.Id[7]))      
 		}
 
 		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
-
-		if (pAC->Rlmt.CheckingState & SK_RLMT_RCS_REPORT_SEG) {
-			SkRlmtCheckSeg(pAC, IoC);
+		if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+			SK_RLMT_RCS_REPORT_SEG) != 0) {
+			SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber);
 		}
 	}
 	else {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_RX,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
 			("SkRlmtPacketReceive: Unknown Packet Type.\n"))
 
 		/* Unknown packet. */
-
 		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
 	}
 	return;
@@ -1625,25 +1383,21 @@
  *	New timeout value.
  */
 RLMT_STATIC SK_U32	SkRlmtCheckPort(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* I/O context */
-SK_U32	PortIdx)	/* port to check */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Port to check */
 {
-	unsigned	i;
-	SK_U32		NewTimeout;
+	unsigned		i;
+	SK_U32			NewTimeout;
 	SK_RLMT_PORT	*pRPort;
-	SK_EVPARA	Para;
+	SK_EVPARA		Para;
 
-	pRPort = &pAC->Rlmt.Port[PortIdx];
+	pRPort = &pAC->Rlmt.Port[PortNumber];
 
 	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 			("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
-				PortIdx,
-				pRPort->PacketsPerTimeSlot))
+				PortNumber, pRPort->PacketsPerTimeSlot))
 
 		/*
 		 * Check segmentation if there was no receive at least twice
@@ -1651,46 +1405,35 @@
 		 * check is not currently running.
 		 */
 
-		if (pRPort->PortNoRx && (pAC->Rlmt.LinksUp > 1) &&
-			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
-			!(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEG)) {
-			pAC->Rlmt.CheckingState |=
+		if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+			(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+			!(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) {
+			pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
 				SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
 		}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 			("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
-				pRPort->PortsSuspect,
-				pRPort->CheckingState & SK_RLMT_PCS_RX))
+				pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX))
 
 		if (pRPort->PortState != SK_RLMT_PS_DOWN) {
-			NewTimeout = TO_SHORTEN(pAC->Rlmt.TimeoutValue);
+			NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue);
 			if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
 				NewTimeout = SK_RLMT_MIN_TO_VAL;
 			}
 
 			if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
-				Para.Para32[0] = PortIdx;
+				Para.Para32[0] = PortNumber;
 				pRPort->CheckingState |= SK_RLMT_PCS_RX;
 
 				/*
-				 * What shall we do if the port checked
-				 * by this one receives our request
-				 * frames?  What's bad - our rx line
-				 * or his tx line?
+				 * What shall we do if the port checked by this one receives
+				 * our request frames?  What's bad - our rx line or his tx line?
 				 */
-
-				SkTimerStart(
-					pAC,
-					IoC,
-					&pRPort->DownRxTimer,
-					SK_RLMT_PORTDOWN_TIM_VAL,
-					SKGE_RLMT,
-					SK_RLMT_PORTDOWN_RX_TIM,
-					Para);
+				Para.Para32[1] = (SK_U32)-1;
+				SkTimerStart(pAC, IoC, &pRPort->DownRxTimer,
+					SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+					SK_RLMT_PORTDOWN_RX_TIM, Para);
 
 				for (i = 0; i < pRPort->PortsChecked; i++) {
 					if (pRPort->PortCheck[i].SuspectTx) {
@@ -1699,19 +1442,10 @@
 					pRPort->PortCheck[i].SuspectTx = SK_TRUE;
 					pRPort->PortsSuspect++;
 					if ((Para.pParaPtr =
-						SkRlmtBuildPacket(
-							pAC,
-							IoC,
-							PortIdx,
-							SK_PACKET_CHECK_TX,
-							&pAC->Addr.Port[PortIdx].CurrentMacAddress,
-							&pRPort->PortCheck[i].CheckAddr)
-							) != NULL) {
-						SkEventQueue(
-							pAC,
-							SKGE_DRV,
-							SK_DRV_RLMT_SEND,
-							Para);
+						SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX,
+							&pAC->Addr.Port[PortNumber].CurrentMacAddress,
+							&pRPort->PortCheck[i].CheckAddr)) != NULL) {
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
 					}
 				}
 			}
@@ -1722,17 +1456,17 @@
 		pRPort->PortNoRx = SK_TRUE;
 	}
 	else {	/* A non-BPDU packet was received. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 			("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
-				PortIdx,
-                                pRPort->PacketsPerTimeSlot -
-					pRPort->BpduPacketsPerTimeSlot,
+				PortNumber,
+				pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot,
 				pRPort->PacketsPerTimeSlot))
 		
-		SkRlmtPortReceives(pAC, IoC, PortIdx);
+		SkRlmtPortReceives(pAC, IoC, PortNumber);
+		if (pAC->Rlmt.CheckSwitch) {
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+
 		NewTimeout = SK_RLMT_DEF_TO_VAL;              
 	}
 
@@ -1755,82 +1489,69 @@
  *	SK_BOOL
  */
 RLMT_STATIC SK_BOOL	SkRlmtSelectBcRx(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_U32	A,	/* active port */
-SK_U32	P,	/* preferred port */
-SK_U32	*N)	/* new active port */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	Active,		/* Active port */
+SK_U32	PrefPort,	/* Preferred port */
+SK_U32	*pSelect)	/* New active port */
 {
 	SK_U64		BcTimeStamp;
 	SK_U32		i;
 	SK_BOOL		PortFound;
 
-        BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */
+	BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */
 	PortFound = SK_FALSE;
 	
 	/* Select port with the latest TimeStamp. */
-
 	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("TimeStamp Port %d: %.08x%.08x.\n",
-			i,
-			*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
-			*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
-		if (!pAC->Rlmt.Port[i].PortDown &&
-			!pAC->Rlmt.Port[i].PortNoRx) {
-			if (!PortFound ||
-				pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
+#ifdef xDEBUG
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("TimeStamp Port %d: %08x %08x.\n",
+				i,
+				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
+				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
+#endif	/* DEBUG */
+		if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) {
+			if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
 				BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
-				*N = i;
+				*pSelect = i;
 				PortFound = SK_TRUE;
 			}
 		}
 	}
 
 	if (PortFound) {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("Port %d received the last broadcast.\n", *N))
+#if 0
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Port %d received the last broadcast.\n", *pSelect))
+#endif	/* 0 */
 
 		/* Look if another port's time stamp is similar. */
-
 		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			if (i == *N) {
+			if (i == *pSelect) {
 				continue;
 			}
-			if (!pAC->Rlmt.Port[i].PortDown &&
-				!pAC->Rlmt.Port[i].PortNoRx &&
+			if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx &&
 				(pAC->Rlmt.Port[i].BcTimeStamp >
-				BcTimeStamp - SK_RLMT_BC_DELTA ||
-				pAC->Rlmt.Port[i].BcTimeStamp
-				+ SK_RLMT_BC_DELTA > BcTimeStamp)) {
+				 BcTimeStamp - SK_RLMT_BC_DELTA ||
+				pAC->Rlmt.Port[i].BcTimeStamp +
+				 SK_RLMT_BC_DELTA > BcTimeStamp)) {
 				PortFound = SK_FALSE;
-				SK_DBG_MSG(
-					pAC,
-					SK_DBGMOD_RLMT,
-					SK_DBGCAT_CTRL,
-					("Port %d received a broadcast %s.\n",
-					i,
-					"at a similar time"))
+#ifdef xDEBUG
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+					("Port %d received a broadcast at a similar time.\n", i))
+#endif	/* DEBUG */
 				break;
 			}
 		}
 	}
 
-#ifdef DEBUG
+#ifdef xDEBUG
 	if (PortFound) {
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_CHECK_SWITCH found Port %d receiving %s.\n",
-				*N,
-				"the substantially latest broadcast"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_CHECK_SWITCH found Port %d receiving the substantially latest broadcast (%d).\n",
+				*pSelect,
+				BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
 	}
 #endif	/* DEBUG */
 
@@ -1852,11 +1573,11 @@
  *	SK_BOOL
  */
 RLMT_STATIC SK_BOOL	SkRlmtSelectNotSuspect(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_U32	A,	/* active port */
-SK_U32	P,	/* preferred port */
-SK_U32	*N)	/* new active port */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	Active,		/* Active port */
+SK_U32	PrefPort,	/* Preferred port */
+SK_U32	*pSelect)	/* New active port */
 {
 	SK_U32		i;
 	SK_BOOL		PortFound;
@@ -1864,32 +1585,25 @@
 	PortFound = SK_FALSE;
 
 	/* Select first port that is PortUp && !SuspectRx. */
-
 	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 		if (!pAC->Rlmt.Port[i].PortDown &&
 			!(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
-			*N = i;
-			if (!pAC->Rlmt.Port[A].PortDown &&
-				!(pAC->Rlmt.Port[A].CheckingState &
-				SK_RLMT_PCS_RX)) {
-				*N = A;
-			}
-			if (!pAC->Rlmt.Port[P].PortDown &&
-				!(pAC->Rlmt.Port[P].CheckingState &
-				SK_RLMT_PCS_RX)) {
-				*N = P;
+			*pSelect = i;
+			if (!pAC->Rlmt.Port[Active].PortDown &&
+				!(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) {
+				*pSelect = Active;
+			}
+			if (!pAC->Rlmt.Port[PrefPort].PortDown &&
+				!(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) {
+				*pSelect = PrefPort;
 			}
 			PortFound = SK_TRUE;
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 				("SK_RLMT_CHECK_SWITCH found Port %d up and not check RX.\n",
-					*N))
+					*pSelect))
 			break;
 		}
 	}
-
 	return (PortFound);
 }	/* SkRlmtSelectNotSuspect */
 
@@ -1908,12 +1622,12 @@
  *	SK_BOOL
  */
 RLMT_STATIC SK_BOOL	SkRlmtSelectUp(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_U32	A,	/* active port */
-SK_U32	P,	/* preferred port */
-SK_U32	*N,	/* new active port */
-SK_BOOL	AutoNegDone)	/* successfully auto-negotiated? */
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
 {
 	SK_U32		i;
 	SK_BOOL		PortFound;
@@ -1921,30 +1635,24 @@
 	PortFound = SK_FALSE;
 
 	/* Select first port that is PortUp. */
-
 	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
 			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
-			*N = i;
-			if (pAC->Rlmt.Port[A].PortState == SK_RLMT_PS_UP &&
-				pAC->GIni.GP[A].PAutoNegFail != AutoNegDone) {
-				*N = A;
-			}
-			if (pAC->Rlmt.Port[P].PortState == SK_RLMT_PS_UP &&
-				pAC->GIni.GP[P].PAutoNegFail != AutoNegDone) {
-				*N = P;
+			*pSelect = i;
+			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+				*pSelect = Active;
+			}
+			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+				*pSelect = PrefPort;
 			}
 			PortFound = SK_TRUE;
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_CHECK_SWITCH found Port %d up.\n",
-					*N))
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_CHECK_SWITCH found Port %d up.\n", *pSelect))
 			break;
 		}
 	}
-
 	return (PortFound);
 }	/* SkRlmtSelectUp */
 
@@ -1963,26 +1671,26 @@
  *	SK_BOOL
  */
 RLMT_STATIC SK_BOOL	SkRlmtSelectGoingUp(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_U32	A,	/* active port */
-SK_U32	P,	/* preferred port */
-SK_U32	*N,	/* new active port */
-SK_BOOL	AutoNegDone)	/* successfully auto-negotiated? */
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
 {
-	SK_U64		GuTimeStamp=0;
+	SK_U64		GuTimeStamp;
 	SK_U32		i;
 	SK_BOOL		PortFound;
 
+	GuTimeStamp = 0;
 	PortFound = SK_FALSE;
 
 	/* Select port that is PortGoingUp for the longest time. */
-
 	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
 			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
-                        GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
-			*N = i;
+			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*pSelect = i;
 			PortFound = SK_TRUE;
 			break;
 		}
@@ -1992,22 +1700,17 @@
 		return (SK_FALSE);
 	}
 
-	for (i = *N + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+	for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
-                        pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
+			pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
 			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
-
-                        GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
-			*N = i;
+			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*pSelect = i;
 		}
 	}
 
-	SK_DBG_MSG(
-		pAC,
-		SK_DBGMOD_RLMT,
-		SK_DBGCAT_CTRL,
-		("SK_RLMT_CHECK_SWITCH found Port %d going up.\n", *N))
-
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_CHECK_SWITCH found Port %d going up.\n", *pSelect))
 	return (SK_TRUE);
 }	/* SkRlmtSelectGoingUp */
 
@@ -2026,12 +1729,12 @@
  *	SK_BOOL
  */
 RLMT_STATIC SK_BOOL	SkRlmtSelectDown(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* I/O context */
-SK_U32	A,	/* active port */
-SK_U32	P,	/* preferred port */
-SK_U32	*N,	/* new active port */
-SK_BOOL	AutoNegDone)	/* successfully auto-negotiated? */
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
 {
 	SK_U32		i;
 	SK_BOOL		PortFound;
@@ -2039,30 +1742,24 @@
 	PortFound = SK_FALSE;
 
 	/* Select first port that is PortDown. */
-
 	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
 		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
 			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
-			*N = i;
-			if (pAC->Rlmt.Port[A].PortState == SK_RLMT_PS_DOWN &&
-				pAC->GIni.GP[A].PAutoNegFail != AutoNegDone) {
-				*N = A;
-			}
-			if (pAC->Rlmt.Port[P].PortState == SK_RLMT_PS_DOWN &&
-				pAC->GIni.GP[P].PAutoNegFail != AutoNegDone) {
-				*N = P;
+			*pSelect = i;
+			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+				*pSelect = Active;
+			}
+			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+				*pSelect = PrefPort;
 			}
 			PortFound = SK_TRUE;
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_CHECK_SWITCH found Port %d down.\n",
-					*N))
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_CHECK_SWITCH found Port %d down.\n", *pSelect))
 			break;
 		}
 	}
-
 	return (PortFound);
 }	/* SkRlmtSelectDown */
 
@@ -2082,58 +1779,50 @@
  *	Nothing.
  */
 RLMT_STATIC void	SkRlmtCheckSwitch(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC)	/* I/O context */
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_U32	NetIdx)	/* Net index */
 {
 	SK_EVPARA	Para;
-	SK_U32		A;
-	SK_U32		P;
+	SK_U32		Active;
+	SK_U32		PrefPort;
 	SK_U32		i;
 	SK_BOOL		PortFound;
 
-	if (pAC->Rlmt.RlmtState == SK_RLMT_RS_INIT) {
-		return;
-	}
-
-	A = pAC->Rlmt.MacActive;	/* Index of active port. */
-	P = pAC->Rlmt.PrefPort;		/* Index of preferred port. */
+	Active = pAC->Rlmt.Net[NetIdx].ActivePort;	/* Index of active port. */
+	PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort;	/* Index of preferred port. */
 	PortFound = SK_FALSE;
+	pAC->Rlmt.CheckSwitch = SK_FALSE;
 
-	if (pAC->Rlmt.LinksUp == 0) {
-
-		/*
-		 * Last link went down - shut down the net.
-		 */
-
-		pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_DOWN;
+	if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) {
+		/* Last link went down - shut down the net. */
+		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN;
 		Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
-		SkEventQueue(
-			pAC,
-			SKGE_DRV,
-			SK_DRV_NET_DOWN,
-			Para);
+		Para.Para32[1] = NetIdx;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para);
 
+		Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+			Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+		Para.Para32[1] = NetIdx;
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
 		return;
-	}
-	else if (pAC->Rlmt.LinksUp == 1 &&
-		pAC->Rlmt.RlmtState == SK_RLMT_RS_NET_DOWN) {
-
+	}	/* pAC->Rlmt.LinksUp == 0 */
+	else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 &&
+		pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) {
 		/* First link came up - get the net up. */
-
-		pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_UP;
+		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP;
 
 		/*
-		 * If pAC->Rlmt.MacActive != Para.Para32[0],
+		 * If pAC->Rlmt.ActivePort != Para.Para32[0],
 		 * the DRV switches to the port that came up.
 		 */
-
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			if (!pAC->Rlmt.Port[i].LinkDown) {
-				if (!pAC->Rlmt.Port[A].LinkDown) {
-					i = A;
+		for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+			if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+				if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) {
+					i = Active;
 				}
-				if (!pAC->Rlmt.Port[P].LinkDown) {
-					i = P;
+				if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) {
+					i = PrefPort;
 				}
 				PortFound = SK_TRUE;
 				break;
@@ -2141,184 +1830,143 @@
 		}
 
 		if (PortFound) {
-			Para.Para32[0] = pAC->Rlmt.MacActive;
-			Para.Para32[1] = i;
-			SkEventQueue(
-				pAC,
-				SKGE_PNMI,
-				SK_PNMI_EVT_RLMT_PORT_SWITCH,
-				Para);
-
-			pAC->Rlmt.MacActive = i;
-			Para.Para32[0] = i;
+			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+			Para.Para32[1] = NetIdx;
+			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+
+			pAC->Rlmt.Net[NetIdx].ActivePort = i;
+			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+			Para.Para32[1] = NetIdx;
 			SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
 
-			if ((Para.pParaPtr = SkRlmtBuildPacket(
-					pAC,
-					IoC,
-					i,
-					SK_PACKET_ANNOUNCE,
-					&pAC->Addr.CurrentMacAddress,
-					&SkRlmtMcAddr)
-				) != NULL) {
-
+			if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+				(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber,
+				SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].
+				CurrentMacAddress, &SkRlmtMcAddr)) != NULL) {
 				/*
-				 * Send packet to RLMT multicast address
-				 * to force switches to learn the new
-				 * location of the address.
+				 * Send announce packet to RLMT multicast address to force
+				 * switches to learn the new location of the logical MAC address.
 				 */
-
-				SkEventQueue(
-					pAC,
-					SKGE_DRV,
-					SK_DRV_RLMT_SEND,
-					Para);
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
 			}
 		}
 		else {
-			SK_ERR_LOG(
-				pAC,
-				SK_ERRCL_SW,
-				SKERR_RLMT_E007,
-				SKERR_RLMT_E007_MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG);
 		}
 
 		return;
-	}
-	else {
-		Para.Para32[0] = A;
+	}	/* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */
+	else {	/* Cannot be reached in dual-net mode. */
+		Para.Para32[0] = Active;
 
 		/*
 		 * Preselection:
-		 *   If RLMT Mode != CheckLinkState
-		 *     select port that received a broadcast frame
-		 *     substantially later than all other ports
-		 *   else select first port that is not SuspectRx
-		 *   else select first port that is PortUp
-		 *   else select port that is PortGoingUp for the longest time
-		 *   else select first port that is PortDown
-		 *   else stop.
+		 *	If RLMT Mode != CheckLinkState
+		 *		select port that received a broadcast frame substantially later
+		 *		than all other ports
+		 *	else select first port that is not SuspectRx
+		 *	else select first port that is PortUp
+		 *	else select port that is PortGoingUp for the longest time
+		 *	else select first port that is PortDown
+		 *	else stop.
 		 *
 		 * For the preselected port:
-		 *   If ActivePort is equal in quality, select ActivePort.
+		 *	If ActivePort is equal in quality, select ActivePort.
 		 *
-		 *   If PrefPort is equal in quality, select PrefPort.
+		 *	If PrefPort is equal in quality, select PrefPort.
 		 *
-		 *   If MacActive != SelectedPort,
-		 *     If old ActivePort is LinkDown,
-		 *       SwitchHard
-		 *     else
-		 *       SwitchSoft
+		 *	If ActivePort != SelectedPort,
+		 *		If old ActivePort is LinkDown,
+		 *			SwitchHard
+		 *		else
+		 *			SwitchSoft
 		 */
-
-		if (pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) {
+		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
 			if (!PortFound) {
-				PortFound = SkRlmtSelectBcRx(pAC, IoC,
-					A, P, &Para.Para32[1]);
+				PortFound = SkRlmtSelectBcRx(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
 			}
 
 			if (!PortFound) {
-				PortFound = SkRlmtSelectNotSuspect(pAC, IoC,
-					A, P, &Para.Para32[1]);
+				PortFound = SkRlmtSelectNotSuspect(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
 			}
-		}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
 
 		if (!PortFound) {
-			PortFound = SkRlmtSelectUp(pAC, IoC,
-				A, P, &Para.Para32[1], AUTONEG_SUCCESS);
+			PortFound = SkRlmtSelectUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
 		}
 
 		if (!PortFound) {
-			PortFound = SkRlmtSelectUp(pAC, IoC,
-				A, P, &Para.Para32[1], AUTONEG_FAILED);
+			PortFound = SkRlmtSelectUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
 		}
 
 		if (!PortFound) {
-			PortFound = SkRlmtSelectGoingUp(pAC, IoC,
-				A, P, &Para.Para32[1], AUTONEG_SUCCESS);
+			PortFound = SkRlmtSelectGoingUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
 		}
 
 		if (!PortFound) {
-			PortFound = SkRlmtSelectGoingUp(pAC, IoC,
-				A, P,&Para.Para32[1], AUTONEG_FAILED);
+			PortFound = SkRlmtSelectGoingUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
 		}
 
-		if (pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) {
+		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
 			if (!PortFound) {
 				PortFound = SkRlmtSelectDown(pAC, IoC,
-					A, P,&Para.Para32[1], AUTONEG_SUCCESS);
+					Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
 			}
 
 			if (!PortFound) {
 				PortFound = SkRlmtSelectDown(pAC, IoC,
-					A, P,&Para.Para32[1], AUTONEG_FAILED);
+					Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
 			}
-		}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
 
 		if (PortFound) {
-			if (Para.Para32[1] != A) {
-				pAC->Rlmt.MacActive = Para.Para32[1];
-				SK_HWAC_LINK_LED(
-					pAC,
-					IoC,
-					Para.Para32[1],
-					SK_LED_ACTIVE);
-				if (pAC->Rlmt.Port[A].LinkDown) {
-					SkEventQueue(
-						pAC,
-						SKGE_DRV,
-						SK_DRV_SWITCH_HARD,
-						Para);
+			if (Para.Para32[1] != Active) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+					("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
+				pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1];
+				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+					Port[Para.Para32[0]]->PortNumber;
+				Para.Para32[1] = pAC->Rlmt.Net[NetIdx].
+					Port[Para.Para32[1]]->PortNumber;
+				SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE);
+				if (pAC->Rlmt.Port[Active].LinkDown) {
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para);
 				}
 				else {
-					SK_HWAC_LINK_LED(
-						pAC,
-						IoC,
-						Para.Para32[0],
-						SK_LED_STANDBY);
-					SkEventQueue(
-						pAC,
-						SKGE_DRV,
-						SK_DRV_SWITCH_SOFT,
-						Para);
+					SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para);
 				}
-				SkEventQueue(
-					pAC,
-					SKGE_PNMI,
-					SK_PNMI_EVT_RLMT_PORT_SWITCH,
-					Para);
-				if ((Para.pParaPtr = SkRlmtBuildPacket(
-						pAC,
-						IoC,
-						Para.Para32[1],
-						SK_PACKET_ANNOUNCE,
-						&pAC->Addr.CurrentMacAddress,
-						&SkRlmtMcAddr)
-					) != NULL) {
-
+				Para.Para32[1] = NetIdx;
+				Para.Para32[0] =
+					pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber;
+				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+					Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+				if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+					(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0],
+					SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress,
+					&SkRlmtMcAddr)) != NULL) {
 					/*
-					 * Send "new" packet to RLMT multicast
-					 * address to force switches to learn
-					 * the new location of the MAC address.
+					 * Send announce packet to RLMT multicast address to force
+					 * switches to learn the new location of the logical
+					 * MAC address.
 					 */
-
-					SkEventQueue(
-						pAC,
-						SKGE_DRV,
-						SK_DRV_RLMT_SEND,
-						Para);
-				}
-			}
-		}
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+				}	/* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */
+			}	/* Para.Para32[1] != Active */
+		}	/* PortFound */
 		else {
-			SK_ERR_LOG(
-				pAC,
-				SK_ERRCL_SW,
-				SKERR_RLMT_E004,
-				SKERR_RLMT_E004_MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG);
 		}
-	}
-
+	}	/* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */
 	return;
 }	/* SkRlmtCheckSwitch */
 
@@ -2338,66 +1986,65 @@
  *	Nothing.
  */
 RLMT_STATIC void	SkRlmtCheckSeg(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC)	/* I/O context */
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_U32	NetIdx)	/* Net number */
 {
-	SK_BOOL	Equal;
-	SK_U32	i, j;
+	SK_EVPARA	Para;
+	SK_RLMT_NET	*pNet;
+	SK_U32		i, j;
+	SK_BOOL		Equal;
 
-	pAC->Rlmt.RootIdSet = SK_FALSE;
+	pNet = &pAC->Rlmt.Net[NetIdx];
+	pNet->RootIdSet = SK_FALSE;
 	Equal = SK_TRUE;
-	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-		if (pAC->Rlmt.Port[i].LinkDown ||
-			!pAC->Rlmt.Port[i].RootIdSet) {
+
+	for (i = 0; i < pNet->NumPorts; i++) {
+		if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) {
 			continue;
 		}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
-				i,
-				pAC->Rlmt.Port[i].Root.Id[0],
-				pAC->Rlmt.Port[i].Root.Id[1],
-				pAC->Rlmt.Port[i].Root.Id[2],
-				pAC->Rlmt.Port[i].Root.Id[3],
-				pAC->Rlmt.Port[i].Root.Id[4],
-				pAC->Rlmt.Port[i].Root.Id[5],
-				pAC->Rlmt.Port[i].Root.Id[6],
-				pAC->Rlmt.Port[i].Root.Id[7]))
-
-		if (!pAC->Rlmt.RootIdSet) {
-			pAC->Rlmt.Root = pAC->Rlmt.Port[i].Root;
-			pAC->Rlmt.RootIdSet = SK_TRUE;
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i,
+				pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1],
+				pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3],
+				pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5],
+				pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7]))
+
+		if (!pNet->RootIdSet) {
+			pNet->Root = pNet->Port[i]->Root;
+			pNet->RootIdSet = SK_TRUE;
 			continue;
 		}
 
 		for (j = 0; j < 8; j ++) {
-			Equal &= pAC->Rlmt.Port[i].Root.Id[j] ==
-				pAC->Rlmt.Root.Id[j];
+			Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j];
 			if (!Equal) {
 				break;
 			}
 		}
 		
 		if (!Equal) {
-			SK_ERR_LOG(
-				pAC,
-				SK_ERRCL_COMM,
-				SKERR_RLMT_E005,
-				SKERR_RLMT_E005_MSG);
-#ifdef SK_PNMI_EVT_SEGMENTATION
-			SkEventQueue(
-				pAC,
-				SKGE_PNMI,
-				SK_PNMI_EVT_SEGMENTATION,
-				Para);
-#endif	/* SK_PNMI_EVT_SEGMENTATION */
-			pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG);
+			Para.Para32[0] = NetIdx;
+			Para.Para32[1] = (SK_U32)-1;
+			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para);
+
+			pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+
+			/* 2000-03-06 RA: New. */
+			Para.Para32[0] = NetIdx;
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL,
+				SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
 			break;
 		}
-	}
+	}	/* for (i = 0; i < pNet->NumPorts; i++) */
+
+	/* 2000-03-06 RA: Moved here. */
+	/* Segmentation check not running anymore. */
+	pNet->CheckingState &= ~SK_RLMT_RCS_SEG;
+
 }	/* SkRlmtCheckSeg */
 
 
@@ -2417,1005 +2064,1340 @@
  *	Nothing
  */
 RLMT_STATIC void	SkRlmtPortStart(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* I/O context */
-SK_U32	PortIdx)	/* event code */
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Port number */
 {
 	SK_EVPARA	Para;
 
-	pAC->Rlmt.Port[PortIdx].PortState = SK_RLMT_PS_LINK_DOWN;
-	pAC->Rlmt.Port[PortIdx].PortStarted = SK_TRUE;
-	pAC->Rlmt.Port[PortIdx].LinkDown = SK_TRUE;
-	pAC->Rlmt.Port[PortIdx].PortDown = SK_TRUE;
-	pAC->Rlmt.Port[PortIdx].CheckingState = 0;
-	pAC->Rlmt.Port[PortIdx].RootIdSet = SK_FALSE;
-	Para.Para32[0] = PortIdx;
+	pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN;
+	pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].CheckingState = 0;
+	pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+	Para.Para32[0] = PortNumber;
+	Para.Para32[1] = (SK_U32)-1;
 	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
 }	/* SkRlmtPortStart */
 
 
 /******************************************************************************
  *
- *	SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *	SkRlmtEvtPortStartTim - PORT_START_TIM
  *
  * Description:
- *	This routine handles PORT- and RLMT-specific events.
+ *	This routine handles PORT_START_TIM events.
  *
  * Context:
  *	runtime, pageable?
  *	may be called after SK_INIT_IO
  *
  * Returns:
- *	0
+ *	Nothing
  */
-int	SkRlmtEvent(
-SK_AC		*pAC,	/* adapter context */
-SK_IOC		IoC,	/* I/O context */
-SK_U32		Event,	/* event code */
-SK_EVPARA	Para)	/* event-specific parameter */
+RLMT_STATIC void	SkRlmtEvtPortStartTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
 {
-	SK_U32		i, j;
-	SK_RLMT_PORT	*pRPort;
-	SK_EVPARA	Para2;
-	SK_MBUF		*pMb;
-	SK_MBUF		*pNextMb;
-	SK_MAC_ADDR	*pOldMacAddr;
-	SK_MAC_ADDR	*pNewMacAddr;
-	SK_U32		Timeout;
-	SK_U32		NewTimeout;
-	SK_U32		PrevRlmtMode;
-
-	switch (Event) {
-	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORTSTART_TIMEOUT Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
-
-		/*
-		 * Used to start non-preferred ports if the preferred one
-		 * does not come up.
-		 * This timeout needs only be set when starting the first
-		 * (preferred) port.
-		 */
+	SK_U32			i;
 
-		if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0]))
 
-			/* PORT_START failed. */
+		if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n"))
+		return;
+	}
 
-			for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-				if (!pAC->Rlmt.Port[i].PortStarted) {
-					SkRlmtPortStart(pAC, IoC, i);
-				}
+	/*
+	 * Used to start non-preferred ports if the preferred one
+	 * does not come up.
+	 * This timeout needs only be set when starting the first
+	 * (preferred) port.
+	 */
+	if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+		/* PORT_START failed. */
+		for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) {
+			if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) {
+				SkRlmtPortStart(pAC, IoC,
+					pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber);
 			}
 		}
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORTSTART_TIMEOUT Event (%d) END.\n", Event))
-		break;
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTSTART_TIMEOUT Event END.\n"))
+}	/* SkRlmtEvtPortStartTim */
 
-	case SK_RLMT_LINK_UP:		/* From SIRQ. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_LINK_UP Port %d Event (%d) BEGIN.\n",
-				Para.Para32[0], Event))
-
-		pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
-
-		if (!pRPort->PortStarted) {
-			SK_ERR_LOG(
-				pAC,
-				SK_ERRCL_SW,
-				SKERR_RLMT_E008,
-				SKERR_RLMT_E008_MSG);
-
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_LINK_UP Event (%d) EMPTY.\n", Event))
-			break;
-		}
 
-		if (!pRPort->LinkDown) {
-			/* RA;:;: Any better solution? */
+/******************************************************************************
+ *
+ *	SkRlmtEvtLinkUp - LINK_UP
+ *
+ * Description:
+ *	This routine handles LLINK_UP events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtLinkUp(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
+{
+	SK_U32			i;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para2;
 
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_LINK_UP Event (%d) EMPTY.\n", Event))
-			break;
-		}
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0]))
 
-		SkTimerStop(pAC, IoC, &pRPort->UpTimer);
-		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
-		SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (!pRPort->PortStarted) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG);
 
-		/* Do something if timer already fired? */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_LINK_UP Event EMPTY.\n"))
+		return;
+	}
 
-		pRPort->LinkDown = SK_FALSE;
-		pRPort->PortState = SK_RLMT_PS_GOING_UP;
-		pRPort->GuTimeStamp = SkOsGetTime(pAC);
-		pRPort->BcTimeStamp = 0;
-		if (pAC->Rlmt.LinksUp == 0) {
-			SK_HWAC_LINK_LED(
-				pAC,
-				IoC,
-				Para.Para32[0],
-				SK_LED_ACTIVE);
-		}
-		else {
-			SK_HWAC_LINK_LED(
-				pAC,
-				IoC,
-				Para.Para32[0],
-				SK_LED_STANDBY);
+	if (!pRPort->LinkDown) {
+		/* RA;:;: Any better solution? */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_UP Event EMPTY.\n"))
+		return;
+	}
+
+	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+	/* Do something if timer already fired? */
+
+	pRPort->LinkDown = SK_FALSE;
+	pRPort->PortState = SK_RLMT_PS_GOING_UP;
+	pRPort->GuTimeStamp = SkOsGetTime(pAC);
+	pRPort->BcTimeStamp = 0;
+	pRPort->Net->LinksUp++;
+	if (pRPort->Net->LinksUp == 1) {
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE);
+	}
+	else {
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+	}
+
+	for (i = 0; i < pRPort->Net->NumPorts; i++) {
+		if (!pRPort->Net->Port[i]->PortStarted) {
+			SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber);
 		}
-		pAC->Rlmt.LinksUp++;
+	}
 
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			if (!pAC->Rlmt.Port[i].PortStarted) {
-				SkRlmtPortStart(pAC, IoC, i);
-			}
+	SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+
+	if (pRPort->Net->LinksUp >= 2) {
+		if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
 		}
+	}
 
-		SkRlmtCheckSwitch(pAC, IoC);
+	/* If the first link comes up, start the periodical RLMT timeout. */
+	if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 &&
+		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) {
+		Para2.Para32[0] = pRPort->Net->NetNumber;
+		Para2.Para32[1] = (SK_U32)-1;
+		SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer,
+			pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2);
+	}
 
-		if (pAC->Rlmt.LinksUp >= 2) {
-			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+	Para2 = Para;
+	Para2.Para32[1] = (SK_U32)-1;
+	SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+		SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2);
+	
+	/* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */
+	if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 &&
+		(Para2.pParaPtr =
+			SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE,
+			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr)
+		) != NULL) {
+		/* Send "new" packet to RLMT multicast address. */
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+	}
+
+	if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) {
+		if ((Para2.pParaPtr =
+			SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) {
+			pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE;
+			pRPort->Net->CheckingState |=
+				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
 
-				/* Build the check chain. */
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
 
-				SkRlmtBuildCheckChain(pAC);
-			}
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer,
+				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
 		}
+	}
 
-		/*
-		 * If the first link comes up, start the periodical
-		 * RLMT timeout.
-		 */
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_UP Event END.\n"))
+}	/* SkRlmtEvtLinkUp */
 
-		if (pAC->GIni.GIMacsFound > 1 && pAC->Rlmt.LinksUp == 1 &&
-			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_OTHERS)) {
-			SkTimerStart(
-				pAC,
-				IoC,
-				&pAC->Rlmt.LocTimer,
-				pAC->Rlmt.TimeoutValue,
-				SKGE_RLMT,
-				SK_RLMT_TIM,
-				Para);
-		}
-
-		SkTimerStart(
-			pAC,
-			IoC,
-			&pRPort->UpTimer,
-			SK_RLMT_PORTUP_TIM_VAL,
-			SKGE_RLMT,
-			SK_RLMT_PORTUP_TIM,
-			Para);
 
-		/*
-		 * Later:
-		 * if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) &&
-		 */
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortUpTim - PORT_UP_TIM
+ *
+ * Description:
+ *	This routine handles PORT_UP_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortUpTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
 
-		if ((pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LINK) &&
-			(Para2.pParaPtr = SkRlmtBuildPacket(
-				pAC,
-				IoC,
-				Para.Para32[0],
-				SK_PACKET_ANNOUNCE,
-				&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress,
-				&SkRlmtMcAddr)
-			) != NULL) {
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0]))
 
-			/* Send "new" packet to RLMT multicast address. */
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Event EMPTY.\n"))
+		return;
+	}
 
-			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
-		}
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0]))
+		return;
+	}
 
-		if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
-			if ((Para2.pParaPtr =
-				SkRlmtBuildSpanningTreePacket(
-					pAC,
-					IoC,
-					Para.Para32[0])
-				) != NULL) {
-				
-				pAC->Rlmt.Port[Para.Para32[0]].RootIdSet =
-					SK_FALSE;
-				pAC->Rlmt.CheckingState |=
-					SK_RLMT_RCS_SEG |
-					SK_RLMT_RCS_REPORT_SEG;
-				
-				SkEventQueue(
-					pAC,
-					SKGE_DRV,
-					SK_DRV_RLMT_SEND,
-					Para2);
-
-				SkTimerStart(
-					pAC,
-					IoC,
-					&pAC->Rlmt.SegTimer,
-					SK_RLMT_SEG_TO_VAL,
-					SKGE_RLMT,
-					SK_RLMT_SEG_TIM,
-					Para);
-			}
+	pRPort->PortDown = SK_FALSE;
+	pRPort->PortState = SK_RLMT_PS_UP;
+	pRPort->Net->PortsUp++;
+	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+		if (pAC->Rlmt.NumNets <= 1) {
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
 		}
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para);
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_LINK_UP Event (%d) END.\n", Event))
-		break;
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTUP_TIM Event END.\n"))
+}	/* SkRlmtEvtPortUpTim */
 
-	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORTUP_TIM Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
-
-		pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
-
-		if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_PORTUP_TIM Port %d Event (%d) EMPTY.\n",
-					Para.Para32[0],
-					Event))
-			break;
-		}
 
-		pRPort->PortDown = SK_FALSE;
-                pRPort->PortState = SK_RLMT_PS_UP;
-		pAC->Rlmt.PortsUp++;
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortDownTim - PORT_DOWN_*
+ *
+ * Description:
+ *	This routine handles PORT_DOWN_* events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortDownX(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Event code */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n",
+			Para.Para32[0], Event))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event EMPTY.\n"))
+		return;
+	}
 
-		if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) {
-			SkRlmtCheckSwitch(pAC, IoC);
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM &&
+		!(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
+		return;
+	}
+	
+	/* Stop port's timers. */
+	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
 
-			SkEventQueue(
-				pAC,
-				SKGE_PNMI,
-				SK_PNMI_EVT_RLMT_PORT_UP,
-				Para);
-		}
+	if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
+		pRPort->PortState = SK_RLMT_PS_DOWN;
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORTUP_TIM Event (%d) END.\n", Event))
-		break;
+	if (!pRPort->PortDown) {
+		pRPort->Net->PortsUp--;
+		pRPort->PortDown = SK_TRUE;
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para);
+	}
 
-	case SK_RLMT_PORTDOWN:		/* From RLMT. */
-	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */
-	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
-
-		pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
-
-		if (!pRPort->PortStarted ||
-			(Event == SK_RLMT_PORTDOWN_TX_TIM &&
-			!(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
-			break;
+	pRPort->PacketsPerTimeSlot = 0;
+	/* pRPort->DataPacketsPerTimeSlot = 0; */
+	pRPort->BpduPacketsPerTimeSlot = 0;
+
+	/*
+	 * RA;:;: To be checked:
+	 * - actions at RLMT_STOP: We should not switch anymore.
+	 */
+	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+		if (Para.Para32[0] ==
+			pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) {
+			/* Active Port went down. */
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
 		}
-		/* Stop port's timers. */
+	}
 
-		SkTimerStop(pAC, IoC, &pRPort->UpTimer);
-		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
-		SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
+}	/* SkRlmtEvtPortDownX */
 
-		if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
-			pRPort->PortState = SK_RLMT_PS_DOWN;
-		}
 
-		if (!pRPort->PortDown) {
-			pAC->Rlmt.PortsUp--;
-			pRPort->PortDown = SK_TRUE;
+/******************************************************************************
+ *
+ *	SkRlmtEvtLinkDown - LINK_DOWN
+ *
+ * Description:
+ *	This routine handles LINK_DOWN events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtLinkDown(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
+{
+	SK_RLMT_PORT	*pRPort;
 
-			SkEventQueue(
-				pAC,
-				SKGE_PNMI,
-				SK_PNMI_EVT_RLMT_PORT_DOWN,
-				Para);
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+		pRPort->Net->LinksUp--;
+		pRPort->LinkDown = SK_TRUE;
+		pRPort->PortState = SK_RLMT_PS_LINK_DOWN;
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF);
+
+		if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) {
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
 		}
 
-		pRPort->PacketsPerTimeSlot = 0;
-		pRPort->DataPacketsPerTimeSlot = 0;
-		pRPort->BpduPacketsPerTimeSlot = 0;
-#if 0
-		pRPort->RlmtChksPerTimeSlot = 0;
-		pRPort->RlmtAcksPerTimeSlot = 0;
-#endif	/* 0 */
+		/* Ensure that port is marked down. */
+		Para.Para32[1] = -1;
+		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para);
+	}
 
-		/*
-		 * RA;:;: To be checked:
-		 * - actions at RLMT_STOP: We should not switch anymore.
-		 */
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_DOWN Event END.\n"))
+}	/* SkRlmtEvtLinkDown */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortAddr - PORT_ADDR
+ *
+ * Description:
+ *	This routine handles PORT_ADDR events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortAddr(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_U32			i, j;
+	SK_RLMT_PORT	*pRPort;
+	SK_MAC_ADDR		*pOldMacAddr;
+	SK_MAC_ADDR		*pNewMacAddr;
 
-		if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) {
-			if (Para.Para32[0] == pAC->Rlmt.MacActive) {
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0]))
 
-				/* Active Port went down. */
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event EMPTY.\n"))
+		return;
+	}
 
-				SkRlmtCheckSwitch(pAC, IoC);
+	/* Port's physical MAC address changed. */
+	pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
+	pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+
+	/*
+	 * NOTE: This is not scalable for solutions where ports are
+	 *	 checked remotely.  There, we need to send an RLMT
+	 *	 address change packet - and how do we ensure delivery?
+	 */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		pRPort = &pAC->Rlmt.Port[i];
+		for (j = 0; j < pRPort->PortsChecked; j++) {
+			if (SK_ADDR_EQUAL(
+				pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) {
+				pRPort->PortCheck[j].CheckAddr = *pNewMacAddr;
 			}
 		}
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
-		break;
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event END.\n"))
+}	/* SkRlmtEvtPortAddr */
 
-	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_LINK_DOWN Port %d Event (%d) BEGIN.\n",
-				Para.Para32[0], Event))
-
-		if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
-			pAC->Rlmt.LinksUp--;
-			pAC->Rlmt.Port[Para.Para32[0]].LinkDown = SK_TRUE;
-			pAC->Rlmt.Port[Para.Para32[0]].PortState =
-					SK_RLMT_PS_LINK_DOWN;
-			SK_HWAC_LINK_LED(
-				pAC,
-				IoC,
-				Para.Para32[0],
-				SK_LED_OFF);
-
-			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
-
-				/* Build the check chain. */
-
-				SkRlmtBuildCheckChain(pAC);
-			}
-
-			/* Ensure that port is marked down. */
-
-			(void)SkRlmtEvent(
-				pAC,
-				IoC,
-				SK_RLMT_PORTDOWN,
-				Para);
-		}
-
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_LINK_DOWN Event (%d) END.\n", Event))
-		break;
 
-	case SK_RLMT_PORT_ADDR:		/* From ADDR. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORT_ADDR Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
-
-		/* Port's physical MAC address changed. */
-
-		pOldMacAddr =
-			&pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
-		pNewMacAddr =
-			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+/******************************************************************************
+ *
+ *	SkRlmtEvtStart - START
+ *
+ * Description:
+ *	This routine handles START events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStart(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_EVPARA	Para2;
+	SK_U32		PortIdx;
+	SK_U32		PortNumber;
 
-		/*
-		 * NOTE: This is not scalable for solutions where ports are
-		 *	 checked remotely.  There, we need to send an RLMT
-		 *	 address change packet - and how do we ensure delivery?
-		 */
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0]))
 
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			pRPort = &pAC->Rlmt.Port[i];
-			for (j = 0; j < pRPort->PortsChecked; j++) {
-				if (SK_ADDR_EQUAL(
-					pRPort->PortCheck[j].CheckAddr.a,
-					pOldMacAddr->a)) {
-					pRPort->PortCheck[j].CheckAddr =
-						*pNewMacAddr;
-				}
-			}
-		}
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PORT_ADDR Event (%d) END.\n", Event))
-		break;
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
 
-	/* ----- RLMT events ----- */
+	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
 
-	case SK_RLMT_START:		/* From DRV. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_START Event (%d) BEGIN.\n", Event))
-
-		if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_START Event (%d) EMPTY.\n", Event))
-			break;
-		}
+	if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("All nets should have been started.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
 
-		if (pAC->Rlmt.PrefPort >= (SK_U32)pAC->GIni.GIMacsFound) {
-			SK_ERR_LOG(
-				pAC,
-				SK_ERRCL_SW,
-				SKERR_RLMT_E009,
-				SKERR_RLMT_E009_MSG);
-
-			/* Change PrefPort to internal default. */
-
-			Para.Para32[0] = 0xFFFFFFFF;
-			(void)SkRlmtEvent(
-				pAC,
-				IoC,
-				SK_RLMT_PREFPORT_CHANGE,
-				Para);
-		}
-#if 0
-		if (pAC->GIni.GIMacsFound == 1 &&
-			pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) {
-			Para.Para32[0] = SK_RLMT_CHECK_LINK;
-			(void)SkRlmtEvent(
-				pAC,
-				IoC,
-				SK_RLMT_MODE_CHANGE,
-				Para);
-		}
-#endif	/* 0 */
-		pAC->Rlmt.LinksUp = 0;
-		pAC->Rlmt.PortsUp = 0;
-		pAC->Rlmt.CheckingState = 0;
-		pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_DOWN;
-
-		SkRlmtPortStart(pAC, IoC, pAC->Rlmt.PrefPort);
-
-		/* Start Timer (for first port only). */
-
-		Para2.Para32[0] = pAC->Rlmt.PrefPort;
-		SkTimerStart(
-			pAC,
-			IoC,
-			&pAC->Rlmt.Port[pAC->Rlmt.PrefPort].UpTimer,
-			SK_RLMT_PORTSTART_TIM_VAL,
-			SKGE_RLMT,
-			SK_RLMT_PORTSTART_TIM,
-			Para2);
-
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_START Event (%d) END.\n", Event))
-		break;
+	if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >=
+		pAC->Rlmt.Net[Para.Para32[0]].NumPorts) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG);
 
-	case SK_RLMT_STOP:		/* From DRV. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_STOP Event (%d) BEGIN.\n", Event))
-
-		if (pAC->Rlmt.RlmtState == SK_RLMT_RS_INIT) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_STOP Event (%d) EMPTY.\n", Event))
-			break;
-		}
+		/* Change PrefPort to internal default. */
+		Para2.Para32[0] = 0xFFFFFFFF;
+		Para2.Para32[1] = Para.Para32[0];
+		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2);
+	}
 
-		/* Stop RLMT timers. */
+	PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort;
+	PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber;
 
-		SkTimerStop(pAC, IoC, &pAC->Rlmt.LocTimer); 
-		SkTimerStop(pAC, IoC, &pAC->Rlmt.SegTimer);
+	pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN;
 
-		/* Stop Net. */
+	/* Start preferred port. */
+	SkRlmtPortStart(pAC, IoC, PortNumber);
 
-		pAC->Rlmt.RlmtState = SK_RLMT_RS_INIT;
-		pAC->Rlmt.RootIdSet = SK_FALSE;
-		Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
-		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+	/* Start Timer (for first port only). */
+	Para2.Para32[0] = PortNumber;
+	Para2.Para32[1] = (SK_U32)-1;
+	SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer,
+		SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2);
 
-		/* Stop ports. */
+	pAC->Rlmt.NetsStarted++;
 
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			if (pAC->Rlmt.Port[i].PortState != SK_RLMT_PS_INIT) {
-				SkTimerStop(
-					pAC,
-					IoC,
-					&pAC->Rlmt.Port[i].UpTimer);
-				SkTimerStop(
-					pAC,
-					IoC,
-					&pAC->Rlmt.Port[i].DownRxTimer);
-				SkTimerStop(
-					pAC,
-					IoC,
-					&pAC->Rlmt.Port[i].DownTxTimer);
-
-				pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
-				pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
-				pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
-				Para2.Para32[0] = i;
-				SkEventQueue(
-					pAC,
-					SKGE_HWAC,
-					SK_HWEV_PORT_STOP,
-					Para2);
-			}
-		}
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event END.\n"))
+}	/* SkRlmtEvtStart */
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_STOP Event (%d) END.\n", Event))
-		break;
 
-	case SK_RLMT_TIM:		/* From RLMT via TIME. */
-#if 0
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_TIM Event (%d) BEGIN.\n", Event))
-#endif	/* 0 */
+/******************************************************************************
+ *
+ *	SkRlmtEvtStop - STOP
+ *
+ * Description:
+ *	This routine handles STOP events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStop(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_EVPARA	Para2;
+	SK_U32		PortNumber;
+	SK_U32		i;
 
-		if (!(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_OTHERS) ||
-			pAC->Rlmt.LinksUp == 0) {
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0]))
 
-			/*
-			 * Mode changed or all links down:
-			 * No more link checking.
-			 */
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
 
-			break;
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.NetsStarted == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("All nets are stopped.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	/* Stop RLMT timers. */
+	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer); 
+	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer);
+
+	/* Stop net. */
+	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT;
+	pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE;
+	Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
+	Para2.Para32[1] = Para.Para32[0];			/* Net# */
+	SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+
+	/* Stop ports. */
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+		if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) {
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer);
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer);
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer);
+
+			pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT;
+			pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE;
+			Para2.Para32[0] = PortNumber;
+			Para2.Para32[1] = (SK_U32)-1;
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2);
 		}
+	}
+
+	pAC->Rlmt.NetsStarted--;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STOP Event END.\n"))
+}	/* SkRlmtEvtStop */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtTim - TIM
+ *
+ * Description:
+ *	This routine handles TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+	SK_U32			Timeout;
+	SK_U32			NewTimeout;
+	SK_U32			PortNumber;
+	SK_U32			i;
 
 #if 0
-                pAC->Rlmt.SwitchCheckCounter--;
-		if (pAC->Rlmt.SwitchCheckCounter == 0) {
-			pAC->Rlmt.SwitchCheckCounter;
-		}
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_TIM Event BEGIN.\n"))
 #endif	/* 0 */
 
-		NewTimeout = SK_RLMT_DEF_TO_VAL;
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			pRPort = &pAC->Rlmt.Port[i];
-			if (!pRPort->LinkDown) {
-				Timeout = SkRlmtCheckPort(pAC, IoC, i);
-				if (Timeout < NewTimeout) {
-					NewTimeout = Timeout;
-				}
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event EMPTY.\n"))
+		return;
+	}
 
-				/*
-				 * This counter should be set to 0 for all
-				 * ports before the first frame is sent in the
-				 * next loop.
-				 */
+	if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 ||
+		pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) {
+		/* Mode changed or all links down: No more link checking. */
+		return;
+	}
 
-				pRPort->PacketsPerTimeSlot = 0;
-				pRPort->DataPacketsPerTimeSlot = 0;
-				pRPort->BpduPacketsPerTimeSlot = 0;
 #if 0
-				pRPort->RlmtChksPerTimeSlot = 0;
-				pRPort->RlmtAcksPerTimeSlot = 0;
+	pAC->Rlmt.SwitchCheckCounter--;
+	if (pAC->Rlmt.SwitchCheckCounter == 0) {
+		pAC->Rlmt.SwitchCheckCounter;
+	}
 #endif	/* 0 */
+
+	NewTimeout = SK_RLMT_DEF_TO_VAL;
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+		pRPort = &pAC->Rlmt.Port[PortNumber];
+		if (!pRPort->LinkDown) {
+			Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber);
+			if (Timeout < NewTimeout) {
+				NewTimeout = Timeout;
 			}
-		}
-		pAC->Rlmt.TimeoutValue = NewTimeout;
 
-		if (pAC->Rlmt.LinksUp > 1) {
 			/*
-			 * If checking remote ports, also send packets if
-			 *   (LinksUp == 1) &&
-			 *   this port checks at least one (remote) port.
+			 * These counters should be set to 0 for all ports before the
+			 * first frame is sent in the next loop.
 			 */
+			pRPort->PacketsPerTimeSlot = 0;
+			/* pRPort->DataPacketsPerTimeSlot = 0; */
+			pRPort->BpduPacketsPerTimeSlot = 0;
+		}
+	}
+	pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout;
 
-			/*
-			 * Must be new loop, as SkRlmtCheckPort can request to
-			 * check segmentation when e.g. checking the last port.
-			 */
+	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) {
+		/*
+		 * If checking remote ports, also send packets if
+		 *   (LinksUp == 1) &&
+		 *   this port checks at least one (remote) port.
+		 */
 
-			for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-				pRPort = &pAC->Rlmt.Port[i];
-				if (!pRPort->LinkDown) {	/* !PortDown? */
-					SkRlmtSend(pAC, IoC, i);
-				}
+		/*
+		 * Must be new loop, as SkRlmtCheckPort can request to
+		 * check segmentation when e.g. checking the last port.
+		 */
+		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+			if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) {
+				SkRlmtSend(pAC, IoC,
+					pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber);
 			}
 		}
+	}
 
-		SkTimerStart(
-			pAC,
-			IoC,
-			&pAC->Rlmt.LocTimer,
-			pAC->Rlmt.TimeoutValue,
-			SKGE_RLMT,
-			SK_RLMT_TIM,
-			Para);
-
-		if (pAC->Rlmt.LinksUp > 1 &&
-			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
-			(pAC->Rlmt.CheckingState & SK_RLMT_RCS_START_SEG)) {
-			SkTimerStart(
-				pAC,
-				IoC,
-				&pAC->Rlmt.SegTimer,
-				SK_RLMT_SEG_TO_VAL,
-				SKGE_RLMT,
-				SK_RLMT_SEG_TIM,
-				Para);
-			pAC->Rlmt.CheckingState &=
-				~SK_RLMT_RCS_START_SEG;
-			pAC->Rlmt.CheckingState |=
-				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
-		}
+	SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer,
+		pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM,
+		Para);
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 &&
+		(pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) {
+		SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer,
+			SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+		pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG;
+		pAC->Rlmt.Net[Para.Para32[0]].CheckingState |=
+			SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+	}
 
 #if 0
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_TIM Event (%d) END.\n", Event))
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event END.\n"))
 #endif	/* 0 */
-		break;
+}	/* SkRlmtEvtTim */
 
-	case SK_RLMT_SEG_TIM:
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_SEG_TIM Event (%d) BEGIN.\n", Event))
 
-#ifdef DEBUG
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			SK_U8		InAddr8[6];
-			SK_U16		*InAddr;
-			SK_ADDR_PORT	*pAPort;
-
-			InAddr = (SK_U16 *)&InAddr8[0];
-			pAPort = &pAC->Addr.Port[i];
-			for (j = 0;
-				j < pAPort->NextExactMatchRlmt;
-				j++) {
-
-				/* Get exact match address j from port i. */
-
-				XM_INADDR(IoC, i, XM_EXM(j), InAddr);
-				SK_DBG_MSG(
-					pAC,
-					SK_DBGMOD_RLMT,
-					SK_DBGCAT_CTRL,
-					("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
-						j,
-       						i,
-       						InAddr8[0],
-       						InAddr8[1],
-       						InAddr8[2],
-       						InAddr8[3],
-       						InAddr8[4],
-       						InAddr8[5],
-						pAPort->Exact[j].a[0],
-						pAPort->Exact[j].a[1],
-						pAPort->Exact[j].a[2],
-						pAPort->Exact[j].a[3],
-						pAPort->Exact[j].a[4],
-						pAPort->Exact[j].a[5]))
-			}
+/******************************************************************************
+ *
+ *	SkRlmtEvtSegTim - SEG_TIM
+ *
+ * Description:
+ *	This routine handles SEG_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtSegTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+#ifdef XDEBUG
+	int j;
+#endif	/* DEBUG */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SEG_TIM Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event EMPTY.\n"))
+		return;
+	}
+
+#ifdef xDEBUG
+	for (j = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
+		SK_ADDR_PORT	*pAPort;
+		SK_U32			k;
+		SK_U16			*InAddr;
+		SK_U8			InAddr8[6];
+
+		InAddr = (SK_U16 *)&InAddr8[0];
+		pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort;
+		for (k = 0; k < pAPort->NextExactMatchRlmt; k++) {
+			/* Get exact match address k from port j. */
+			XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+				XM_EXM(k), InAddr);
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+					k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+					InAddr8[0], InAddr8[1], InAddr8[2],
+					InAddr8[3], InAddr8[4], InAddr8[5],
+					pAPort->Exact[k].a[0], pAPort->Exact[k].a[1],
+					pAPort->Exact[k].a[2], pAPort->Exact[k].a[3],
+					pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
 		}
+	}
 #endif	/* DEBUG */
 				   
-		pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_SEG;
+	SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
 
-		SkRlmtCheckSeg(pAC, IoC);
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event END.\n"))
+}	/* SkRlmtEvtSegTim */
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_SEG_TIM Event (%d) END.\n", Event))
-		break;
 
-	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PACKET_RECEIVED Event (%d) BEGIN.\n", Event))
+/******************************************************************************
+ *
+ *	SkRlmtEvtPacketRx - PACKET_RECEIVED
+ *
+ * Description:
+ *	This routine handles PACKET_RECEIVED events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPacketRx(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_MBUF *pMb */
+{
+	SK_MBUF	*pMb;
+	SK_MBUF	*pNextMb;
+	SK_U32	NetNumber;
+
+#if 0
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n"))
+#endif	/* 0 */
 
-		/* Should we ignore frames during port switching? */
+	/* Should we ignore frames during port switching? */
 
 #ifdef DEBUG
-		pMb = Para.pParaPtr;
-		if (pMb == NULL) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("No mbuf.\n"))
-		}
-		else if (pMb->pNext != NULL) {
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("More than one mbuf or pMb->pNext not set.\n"))
-		}
+	pMb = Para.pParaPtr;
+	if (pMb == NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n"))
+	}
+	else if (pMb->pNext != NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("More than one mbuf or pMb->pNext not set.\n"))
+	}
 #endif	/* DEBUG */
 
-		for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
-			pNextMb = pMb->pNext;
-			pMb->pNext = NULL;
+	for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
+		pNextMb = pMb->pNext;
+		pMb->pNext = NULL;
+
+		NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber;
+		if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) {
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		}
+		else {
 			SkRlmtPacketReceive(pAC, IoC, pMb);
 		}
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PACKET_RECEIVED Event (%d) END.\n", Event))
-		break;
+#if 0
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PACKET_RECEIVED Event END.\n"))
+#endif	/* 0 */
+}	/* SkRlmtEvtPacketRx */
 
-	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_STATS_CLEAR Event (%d) BEGIN.\n", Event))
 
-		/* Clear statistics for virtual and physical ports. */
+/******************************************************************************
+ *
+ *	SkRlmtEvtStatsClear - STATS_CLEAR
+ *
+ * Description:
+ *	This routine handles STATS_CLEAR events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStatsClear(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_U32			i;
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_CLEAR Event BEGIN.\n"))
 
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-			pAC->Rlmt.Port[i].TxHelloCts = 0;
-			pAC->Rlmt.Port[i].RxHelloCts = 0;
-			pAC->Rlmt.Port[i].TxSpHelloReqCts = 0;
-			pAC->Rlmt.Port[i].RxSpHelloCts = 0;
-		}
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+		return;
+	}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_STATS_CLEAR Event (%d) END.\n", Event))
-		break;
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+		return;
+	}
+
+	/* Clear statistics for logical and physical ports. */
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		pRPort =
+			&pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber];
+		pRPort->TxHelloCts = 0;
+		pRPort->RxHelloCts = 0;
+		pRPort->TxSpHelloReqCts = 0;
+		pRPort->RxSpHelloCts = 0;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_CLEAR Event END.\n"))
+}	/* SkRlmtEvtStatsClear */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStatsUpdate - STATS_UPDATE
+ *
+ * Description:
+ *	This routine handles STATS_UPDATE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStatsUpdate(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+		return;
+	}
 
-	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */
 #if 0
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_STATS_UPDATE Event (%d) BEGIN.\n", Event))
-
-		/* Update statistics. */
-
-		/* Currently always up-to-date. */
-
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_STATS_UPDATE Event (%d) END.\n", Event))
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
+
+	/* Update statistics - currently always up-to-date. */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event END.\n"))
 #endif	/* 0 */
-		break;
+}	/* SkRlmtEvtStatsUpdate */
 
-	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PREFPORT_CHANGE to Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
 
-		/* 0xFFFFFFFF == auto-mode. */
+/******************************************************************************
+ *
+ *	SkRlmtEvtPrefportChange - PREFPORT_CHANGE
+ *
+ * Description:
+ *	This routine handles PREFPORT_CHANGE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPrefportChange(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortIndex; SK_U32 NetNumber */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[1]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+		return;
+	}
 
-		if (Para.Para32[0] == 0xFFFFFFFF) {
-			pAC->Rlmt.PrefPort = SK_RLMT_DEF_PREF_PORT;
-		}
-		else {
-			if (Para.Para32[0] >= (SK_U32)pAC->GIni.GIMacsFound) {
-				SK_ERR_LOG(
-					pAC,
-					SK_ERRCL_SW,
-					SKERR_RLMT_E010,
-					SKERR_RLMT_E010_MSG);
-
-				SK_DBG_MSG(
-					pAC,
-					SK_DBGMOD_RLMT,
-					SK_DBGCAT_CTRL,
-					("SK_RLMT_PREFPORT_CHANGE Event (%d) EMPTY.\n", Event))
-				break;
-			}
+	/* 0xFFFFFFFF == auto-mode. */
+	if (Para.Para32[0] == 0xFFFFFFFF) {
+		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT;
+	}
+	else {
+		if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG);
 
-			pAC->Rlmt.PrefPort = Para.Para32[0];
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+			return;
 		}
 
-		pAC->Rlmt.MacPreferred = Para.Para32[0];
+		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0];
+	}
 
-		SkRlmtCheckSwitch(pAC, IoC);
+	pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0];
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_PREFPORT_CHANGE Event (%d) END.\n", Event))
-		break;
+	if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+		SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]);
+	}
 
-	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_MODE_CHANGE Event (%d) BEGIN.\n", Event))
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PREFPORT_CHANGE Event END.\n"))
+}	/* SkRlmtEvtPrefportChange */
 
-		if (pAC->GIni.GIMacsFound < 2) {
-			pAC->Rlmt.RlmtMode = SK_RLMT_CHECK_LINK;
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("Forced RLMT mode to CLS on single link adapter.\n"))
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_RLMT,
-				SK_DBGCAT_CTRL,
-				("SK_RLMT_MODE_CHANGE Event (%d) EMPTY.\n",
-					Event))
-			break;
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtSetNets - SET_NETS
+ *
+ * Description:
+ *	This routine handles SET_NETS events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtSetNets(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NumNets; SK_U32 -1 */
+{
+	int i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SET_NETS Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS ||
+		Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad number of nets: %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == pAC->Rlmt.NumNets) {	/* No change. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	/* Entering and leaving dual mode only allowed while nets are stopped. */
+	if (pAC->Rlmt.NetsStarted > 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Changing dual mode only allowed while all nets are stopped.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == 1) {
+		if (pAC->Rlmt.NumNets > 1) {
+			/* Clear logical MAC addr from second net's active port. */
+			(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+				Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL);
+			pAC->Rlmt.Net[1].NumPorts = 0;
+		}
+
+		pAC->Rlmt.NumNets = Para.Para32[0];
+		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0];
+		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("RLMT: Changed to one net with two ports.\n"))
+	}
+	else if (Para.Para32[0] == 2) {
+		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1];
+		pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1;
+		pAC->Rlmt.Net[0].NumPorts =
+			pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts;
+		
+		pAC->Rlmt.NumNets = Para.Para32[0];
+		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		/* Set logical MAC addr on second net's active port. */
+		(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+			Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL);
+
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("RLMT: Changed to two nets with one port each.\n"))
+	}
+	else {
+		/* Not implemented for more than two nets. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SetNets not implemented for more than two nets.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SET_NETS Event END.\n"))
+}	/* SkRlmtSetNets */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtModeChange - MODE_CHANGE
+ *
+ * Description:
+ *	This routine handles MODE_CHANGE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtModeChange(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NewMode; SK_U32 NetNumber */
+{
+	SK_EVPARA	Para2;
+	SK_U32		i;
+	SK_U32		PrevRlmtMode;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_MODE_CHANGE Event BEGIN.\n"))
+
+	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[1]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	Para.Para32[0] |= SK_RLMT_CHECK_LINK;
+
+	if (pAC->Rlmt.Net[Para.Para32[1]].NumPorts < 2 &&
+		Para.Para32[0] != SK_RLMT_MODE_CLS) {
+		pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS;
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Forced RLMT mode to CLS on single port net.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	/* Update RLMT mode. */
+	PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode;
+	pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0];
+
+	if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
+		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		/* SK_RLMT_CHECK_LOC_LINK bit changed. */
+		if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 &&
+			pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 &&
+			pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) {
+			/* 20001207 RA: Was "PortsUp == 1". */
+			Para2.Para32[0] = Para.Para32[1];
+			Para2.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer,
+				pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue,
+				SKGE_RLMT, SK_RLMT_TIM, Para2);
 		}
+	}
 
-		/* Update RLMT mode. */
+	if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
+		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) {
+		/* SK_RLMT_CHECK_SEG bit changed. */
+		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) {
+			(void)SkAddrMcClear(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+				SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
 
-		PrevRlmtMode = pAC->Rlmt.RlmtMode;
-		pAC->Rlmt.RlmtMode = Para.Para32[0] | SK_RLMT_CHECK_LINK;
+			/* Add RLMT MC address. */
+			(void)SkAddrMcAdd(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+				&SkRlmtMcAddr, SK_ADDR_PERMANENT);
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("RLMT: Changed Mode to %X.\n", pAC->Rlmt.RlmtMode))
-
-		if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
-			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
-			if (!(PrevRlmtMode & SK_RLMT_CHECK_OTHERS) &&
-				pAC->GIni.GIMacsFound > 1 &&
-				pAC->Rlmt.PortsUp == 1) {
-				SkTimerStart(
-					pAC,
-					IoC,
-					&pAC->Rlmt.LocTimer,
-					pAC->Rlmt.TimeoutValue,
-					SKGE_RLMT,
-					SK_RLMT_TIM,
-					Para);
-			}
-		}
-
-		if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
-			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG)) {
-
-			for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-				(void)SkAddrMcClear(
-					pAC,
-					IoC,
-					i,
-					SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
-
-				/* Add RLMT MC address. */
-
-				(void)SkAddrMcAdd(
-					pAC,
-					IoC,
-					i,
-					&SkRlmtMcAddr,
-					SK_ADDR_PERMANENT);
-
-				if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
-					/* Add BPDU MC address. */
-
-					(void)SkAddrMcAdd(
-						pAC,
-						IoC,
-						i,
-						&BridgeMcAddr,
-						SK_ADDR_PERMANENT);
-
-					if (pAC->Rlmt.RlmtState !=
-						SK_RLMT_RS_INIT) {
-						if (!pAC->Rlmt.Port[i].LinkDown &&
-							(Para2.pParaPtr =
-							SkRlmtBuildSpanningTreePacket(
-								pAC,
-								IoC,
-								i)
-							) != NULL) {
-							
-							pAC->Rlmt.Port[i
-								].RootIdSet =
-								SK_FALSE;
-
-							SkEventQueue(
-								pAC,
-								SKGE_DRV,
-								SK_DRV_RLMT_SEND,
-								Para2);
-						}
+			if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode &
+				SK_RLMT_CHECK_SEG) != 0) {
+				/* Add BPDU MC address. */
+				(void)SkAddrMcAdd(pAC, IoC,
+					pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+					&BridgeMcAddr, SK_ADDR_PERMANENT);
+
+				if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+					if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown &&
+						(Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(
+						pAC, IoC, i)) != NULL) {
+						pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet =
+							SK_FALSE;
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
 					}
 				}
-
-				(void)SkAddrMcUpdate(pAC, IoC, i);
 			}
+			(void)SkAddrMcUpdate(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber);
+		}	/* for ... */
+
+		if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) {
+			Para2.Para32[0] = Para.Para32[1];
+			Para2.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer,
+				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2);
+		}
+	}	/* SK_RLMT_CHECK_SEG bit changed. */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event END.\n"))
+}	/* SkRlmtEvtModeChange */
 
-			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
-				SkTimerStart(
-					pAC,
-					IoC,
-					&pAC->Rlmt.SegTimer,
-					SK_RLMT_SEG_TO_VAL,
-					SKGE_RLMT,
-					SK_RLMT_SEG_TIM,
-					Para);
-			}
-		}
 
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
-			("SK_RLMT_MODE_CHANGE Event (%d) END.\n", Event))
+/******************************************************************************
+ *
+ *	SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *
+ * Description:
+ *	This routine calls subroutines to handle PORT- and RLMT-specific events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	0
+ */
+int	SkRlmtEvent(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Event code */
+SK_EVPARA	Para)	/* Event-specific parameter */
+{
+	switch (Event) {
+	
+	/* ----- PORT events ----- */
+
+	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortStartTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_LINK_UP:		/* From SIRQ. */
+		SkRlmtEvtLinkUp(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortUpTim(pAC, IoC, Para);
 		break;
+	case SK_RLMT_PORTDOWN:			/* From RLMT. */
+	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */
+	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortDownX(pAC, IoC, Event, Para);
+		break;
+	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */
+		SkRlmtEvtLinkDown(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORT_ADDR:		/* From ADDR. */
+		SkRlmtEvtPortAddr(pAC, IoC, Para);
+		break;
+
+	/* ----- RLMT events ----- */
+
+	case SK_RLMT_START:		/* From DRV. */
+		SkRlmtEvtStart(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STOP:		/* From DRV. */
+		SkRlmtEvtStop(pAC, IoC, Para);
+		break;
+	case SK_RLMT_TIM:		/* From RLMT via TIME. */
+		SkRlmtEvtTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_SEG_TIM:
+		SkRlmtEvtSegTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */
+		SkRlmtEvtPacketRx(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */
+		SkRlmtEvtStatsClear(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */
+		SkRlmtEvtStatsUpdate(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */
+		SkRlmtEvtPrefportChange(pAC, IoC, Para);
+		break;
+	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */
+		SkRlmtEvtModeChange(pAC, IoC, Para);
+		break;
+	case SK_RLMT_SET_NETS:	/* From DRV. */
+		SkRlmtEvtSetNets(pAC, IoC, Para);
+		break;
+
+	/* ----- Unknown events ----- */
 
 	default:	/* Create error log entry. */
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_RLMT,
-			SK_DBGCAT_CTRL,
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 			("Unknown RLMT Event %d.\n", Event))
-
-		SK_ERR_LOG(
-			pAC,
-			SK_ERRCL_SW,
-			SKERR_RLMT_E003,
-			SKERR_RLMT_E003_MSG);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG);
 		break;
-	}
+	}	/* switch() */
 
 	return (0);       
 }	/* SkRlmtEvent */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/sktimer.c linux/drivers/net/sk98lin/sktimer.c
--- v2.4.6/linux/drivers/net/sk98lin/sktimer.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/sktimer.c	Wed Jul  4 11:50:39 2001
@@ -1,23 +1,32 @@
 /******************************************************************************
  *
  * Name:	sktimer.c
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.12 $
- * Date:	$Date: 1999/11/22 13:38:51 $
+ * Project:	PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.11 $
+ * Date:	$Date: 1998/12/17 13:24:13 $
  * Purpose:	High level timer functions.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1989-1998 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	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; either version 2 of the License, or
- *	(at your option) any later version.
- *
+ *	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
+ *	The copyright notice above does not evidence any
+ *	actual or intended publication of such source code.
+ *
+ *	This Module contains Proprietary Information of SysKonnect
+ *	and should be treated as Confidential.
+ *
+ *	The information in this file is provided for the exclusive use of
+ *	the licensees of SysKonnect.
+ *	Such users have the right to use, modify, and incorporate this code
+ *	into products for purposes authorized by the license agreement
+ *	provided they include this notice and the associated copyright notice
+ *	with any such product.
  *	The information in this file is provided "AS IS" without warranty.
  *
  ******************************************************************************/
@@ -27,9 +36,6 @@
  * History:
  *
  *	$Log: sktimer.c,v $
- *	Revision 1.12  1999/11/22 13:38:51  cgoos
- *	Changed license header to GPL.
- *	
  *	Revision 1.11  1998/12/17 13:24:13  gklug
  *	fix: restart problem: do NOT destroy timer queue if init 1 is done
  *	
@@ -76,7 +82,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skvpd.c linux/drivers/net/sk98lin/skvpd.c
--- v2.4.6/linux/drivers/net/sk98lin/skvpd.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skvpd.c	Wed Jul  4 11:50:39 2001
@@ -2,15 +2,15 @@
  *
  * Name:	skvpd.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.27 $
- * Date:	$Date: 2000/08/10 11:29:06 $
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 2000/06/13 08:00:01 $
  * Purpose:	Shared software to read and write VPD data
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect,
+ *	(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
@@ -27,12 +27,6 @@
  * History:
  *
  *	$Log: skvpd.c,v $
- *	Revision 1.27  2000/08/10 11:29:06  rassmann
- *	Editorial changes.
- *	Preserving 32-bit alignment in structs for the adapter context.
- *	Removed unused function VpdWriteDword() (#if 0).
- *	Made VpdReadKeyword() available for SKDIAG only.
- *	
  *	Revision 1.26  2000/06/13 08:00:01  mkarl
  *	additional cast to avoid compile problems in 64 bit environment
  *	
@@ -72,7 +66,7 @@
  *	
  *	Revision 1.14  1998/10/28 07:20:38  gklug
  *	chg: Interface functions to use IoC as parameter as well
- *	fix: VpdRead/WriteDWord now returns SK_U32
+ *	fix: VpdRead/WriteDWord now return SK_U32
  *	chg: VPD_IN/OUT names conform to SK_IN/OUT
  *	add: usage of VPD_IN/OUT8 macros
  *	add: VpdRead/Write Stream functions to r/w a stream of data
@@ -130,7 +124,7 @@
 	Please refer skvpd.txt for infomation how to include this module
  */
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skvpd.c,v 1.27 2000/08/10 11:29:06 rassmann Exp $ (C) SK";
+	"@(#)$Id: skvpd.c,v 1.26 2000/06/13 08:00:01 mkarl Exp $ (C) SK" ;
 
 #include "h/skdrv1st.h"
 #include "h/sktypes.h"
@@ -144,9 +138,9 @@
 static SK_VPD_PARA	*vpd_find_para(
 	SK_AC	*pAC,
 	char		*key,
-	SK_VPD_PARA *p);
+	SK_VPD_PARA *p) ;
 #else	/* SK_KR_PROTO */
-static SK_VPD_PARA	*vpd_find_para();
+static SK_VPD_PARA	*vpd_find_para() ;
 #endif	/* SK_KR_PROTO */
 
 /*
@@ -161,29 +155,28 @@
 SK_IOC		IoC,	/* IO Context */
 int		event)	/* event to wait for (VPD_READ / VPD_write) completion*/
 {
-	SK_U64	start_time;
-	SK_U16	state;
+	SK_U64	start_time ;
+	SK_U16	state ;
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd wait for %s\n",event?"Write":"Read"));
-	start_time = SkOsGetTime(pAC);
+		("vpd wait for %s\n",event?"Write":"Read")) ;
+	start_time = SkOsGetTime(pAC) ;
 	do {
 		if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC/16) {
-			VPD_STOP(pAC,IoC);
+			VPD_STOP(pAC,IoC) ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
 				SK_DBGCAT_FATAL|SK_DBGCAT_ERR,
-				("ERROR:vpd wait timeout\n"));
-			return(1);
+				("ERROR:vpd wait timeout\n")) ;
+			return(1) ;
 		}
-		VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state);
+		VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state) ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-			("state = %x, event %x\n",state,event));
-	} while((int)(state & PCI_VPD_FLAG) == event);
+			("state = %x, event %x\n",state,event)) ;
+	} while((int)(state & PCI_VPD_FLAG) == event) ;
 
-	return(0);
+	return(0) ;
 }
 
-#ifdef SKDIAG
 
 /*
  * Read the dword at address 'addr' from the VPD EEPROM.
@@ -200,31 +193,27 @@
 SK_IOC		IoC,	/* IO Context */
 int		addr)	/* VPD address */
 {
-	SK_U32	Rtv;
+	SK_U32	Rtv ;
 
 	/* start VPD read */
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd read dword at 0x%x\n",addr));
-	addr &= ~VPD_WRITE;		/* ensure the R/W bit is set to read */
+		("vpd read dword at 0x%x\n",addr)) ;
+	addr &= ~VPD_WRITE ;		/* ensure the R/W bit is set to read */
 
-	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr);
+	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr) ;
 
 	/* ignore return code here */
-	(void)VpdWait(pAC,IoC,VPD_READ);
+	(void)VpdWait(pAC,IoC,VPD_READ) ;
 
 	/* Don't swap here, it's a data stream of bytes */
-	Rtv = 0;
+	Rtv = 0 ;
 
-	VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv);
+	VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv) ;
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd read dword data = 0x%x\n",Rtv));
-	return (Rtv);
+		("vpd read dword data = 0x%x\n",Rtv)) ;
+	return (Rtv) ;
 }
 
-#endif	// SKDIAG
-
-#if 0
-
 /*
 	Write the dword 'data' at address 'addr' into the VPD EEPROM, and
 	verify that the data is written.
@@ -244,8 +233,8 @@
 
 
  Returns	0:	success
-			1:	error,	I2C transfer does not terminate
-			2:	error,	data verify error
+		1:	error,	I2C transfer does not terminate
+		2:	error,	data verify error
 
  */
 static int	VpdWriteDWord(
@@ -257,30 +246,28 @@
 	/* start VPD write */
 	/* Don't swap here, it's a data stream of bytes */
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data));
-	VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data);
+		("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data)) ;
+	VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data) ;
 	/* But do it here */
-	addr |= VPD_WRITE;
+	addr |= VPD_WRITE ;
 
-	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE));
+	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)) ;
 
 	/* this may take up to 10,6 ms */
 	if (VpdWait(pAC,IoC,VPD_WRITE)) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("Write Timed Out\n"));
-		return(1);
-	};
+			("Write Timed Out\n")) ;
+		return(1) ;
+	} ;
 
 	/* verify data */
 	if (VpdReadDWord(pAC,IoC,addr) != data) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL,
-			("Data Verify Error\n"));
-		return(2);
+			("Data Verify Error\n")) ;
+		return(2) ;
 	}
-	return(0);
-}	/* VpdWriteDWord */
-
-#endif	/* 0 */
+	return(0) ;
+}
 
 /*
  *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
@@ -295,12 +282,12 @@
 int		Addr,	/* VPD start address */
 int		Len)	/* number of bytes to read / to write */
 {
-	int		i;
-	int		j;
-	SK_U16		AdrReg;
-	int		Rtv;
+	int		i ;
+	int		j ;
+	SK_U16		AdrReg ;
+	int		Rtv ;
 	SK_U8		* pComp;	/* Compare pointer */
-	SK_U8		Data;		/* Input Data for Compare */
+	SK_U8		Data ;		/* Input Data for Compare */
 
 	/* Init Compare Pointer */
 	pComp = (SK_U8 *) buf;
@@ -312,56 +299,56 @@
 			 * So it is initialized even if only a few bytes
 			 * are written.
 			 */
-			AdrReg = (SK_U16) Addr;
-			AdrReg &= ~VPD_WRITE;	/* READ operation */
+			AdrReg = (SK_U16) Addr ;
+			AdrReg &= ~VPD_WRITE ;	/* READ operation */
 
-			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg);
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
 
 			/* ignore return code here */
-			Rtv = VpdWait(pAC,IoC,VPD_READ);
+			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
 			if (Rtv != 0) {
-				return(i);
+				return(i) ;
 			}
 		}
 
 		/* Write current Byte */
 		VPD_OUT8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)),
-				*(SK_U8*)buf);
+				*(SK_U8*)buf) ;
 
 		if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
 			/* New Address needs to be written to VPD_ADDR reg */
-			AdrReg = (SK_U16) Addr;
+			AdrReg = (SK_U16) Addr ;
 			Addr += sizeof(SK_U32);
-			AdrReg |= VPD_WRITE;	/* WRITE operation */
+			AdrReg |= VPD_WRITE ;	/* WRITE operation */
 
-			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg);
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
 
 			/* Wait for termination */
-			Rtv = VpdWait(pAC,IoC,VPD_WRITE);
+			Rtv = VpdWait(pAC,IoC,VPD_WRITE) ;
 			if (Rtv != 0) {
 				SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-					("Write Timed Out\n"));
-				return(i - (i%sizeof(SK_U32)));
+					("Write Timed Out\n")) ;
+				return(i - (i%sizeof(SK_U32))) ;
 			}
 
 			/*
 			 * Now re-read to verify
 			 */
-			AdrReg &= ~VPD_WRITE;	/* READ operation */
+			AdrReg &= ~VPD_WRITE ;	/* READ operation */
 
-			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg);
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
 
 			/* Wait for termination */
-			Rtv = VpdWait(pAC,IoC,VPD_READ);
+			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
 			if (Rtv != 0) {
 				SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-					("Verify Timed Out\n"));
-				return(i - (i%sizeof(SK_U32)));
+					("Verify Timed Out\n")) ;
+				return(i - (i%sizeof(SK_U32))) ;
 			}
 
 			for (j = 0; j <= (int) (i%sizeof(SK_U32));
 				j ++, pComp ++ ) {
-				VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data);
+				VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data) ;
 				if (Data != *pComp) {
 					/* Verify Error */
 					SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
@@ -391,31 +378,31 @@
 int		Addr,	/* VPD start address */
 int		Len)	/* number of bytes to read / to write */
 {
-	int		i;
-	SK_U16		AdrReg;
-	int		Rtv;
+	int		i ;
+	SK_U16		AdrReg ;
+	int		Rtv ;
 
 	for (i=0; i < Len; i ++, buf++) {
 		if ((i%sizeof(SK_U32)) == 0) {
 			/* New Address needs to be written to VPD_ADDR reg */
-			AdrReg = (SK_U16) Addr;
+			AdrReg = (SK_U16) Addr ;
 			Addr += sizeof(SK_U32);
-			AdrReg &= ~VPD_WRITE;	/* READ operation */
+			AdrReg &= ~VPD_WRITE ;	/* READ operation */
 
-			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg);
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
 
 			/* ignore return code here */
-			Rtv = VpdWait(pAC,IoC,VPD_READ);
+			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
 			if (Rtv != 0) {
-				return(i);
+				return(i) ;
 			}
 
 		}
 		VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)),
-			(SK_U8 *)buf);
+			(SK_U8 *)buf) ;
 	}
 
-	return(Len);
+	return(Len) ;
 }
 
 /*
@@ -432,29 +419,29 @@
 int		len,	/* number of bytes to read / to write */
 int		dir)	/* transfer direction may be VPD_READ or VPD_WRITE */
 {
-	int		Rtv;	/* Return value */
-	int		vpd_rom_size;
-	SK_U32		our_reg2;
+	int		Rtv ;	/* Return value */
+	int		vpd_rom_size ;
+	SK_U32		our_reg2 ;
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
 		("vpd %s block, addr = 0x%x, len = %d\n",
-		dir?"write":"read",addr,len));
+		dir?"write":"read",addr,len)) ;
 
 	if (len == 0)
-		return (0);
+		return (0) ;
 
-	VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2);
+	VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ;
 	vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
 	if (addr > vpd_rom_size - 4) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL,
 			("Address error: 0x%x, exp. < 0x%x\n",
-			addr, vpd_rom_size - 4));
-		return (0);
+			addr, vpd_rom_size - 4)) ;
+		return (0) ;
 	}
 	if (addr + len > vpd_rom_size) {
-		len = vpd_rom_size - addr;
+		len = vpd_rom_size - addr ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("Warning: len was cut to %d\n",len));
+			("Warning: len was cut to %d\n",len)) ;
 	}
 
 	if (dir == VPD_READ) {
@@ -463,7 +450,7 @@
 		Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
 	}
 
-	return (Rtv);
+	return (Rtv) ;
 }
 
 #ifdef SKDIAG
@@ -480,7 +467,7 @@
 int		addr,	/* start reading at the VPD address */
 int		len)	/* number of bytes to read */
 {
-	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ));
+	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)) ;
 }
 
 /*
@@ -495,7 +482,7 @@
 int		addr,	/* start writing at the VPD address */
 int		len)	/* number of bytes to write */
 {
-	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE));
+	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)) ;
 }
 #endif	/* SKDIAG */
 
@@ -512,64 +499,64 @@
 SK_AC		*pAC,	/* Adapters context */
 SK_IOC		IoC)	/* IO Context */
 {
-	SK_VPD_PARA *r, rp;	/* RW or RV */
-	int		i;
-	unsigned char	x;
+	SK_VPD_PARA *r, rp ;	/* RW or RV */
+	int		i ;
+	unsigned char	x ;
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. "));
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")) ;
 	/* read the VPD data into the VPD buffer */
 	if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf,0,VPD_SIZE,VPD_READ)
 		!= VPD_SIZE) {
 
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("Block Read Error\n"));
-		return(1);
+			("Block Read Error\n")) ;
+		return(1) ;
 	}
 
 	/* find the end tag of the RO area */
 	if (!(r = vpd_find_para(pAC,VPD_RV,&rp))) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Encoding Error: RV Tag not found\n"));
-		return (1);
+			("Encoding Error: RV Tag not found\n")) ;
+		return (1) ;
 	}
 	if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Encoding Error: Invalid VPD struct size\n"));
-		return (1);
+			("Encoding Error: Invalid VPD struct size\n")) ;
+		return (1) ;
 	}
-	pAC->vpd.v.vpd_free_ro = r->p_len - 1;
+	pAC->vpd.v.vpd_free_ro = r->p_len - 1 ;
 
 	/* test the checksum */
 	for (i = 0, x = 0; (unsigned)i<=(unsigned)VPD_SIZE/2 - r->p_len; i++) {
-		x += pAC->vpd.vpd_buf[i];
+		x += pAC->vpd.vpd_buf[i] ;
 	}
 	if (x != 0) {
 		/* checksum error */
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("VPD Checksum Error\n"));
-		return (1);
+			("VPD Checksum Error\n")) ;
+		return (1) ;
 	}
 
 	/* find and check the end tag of the RW area */
 	if (!(r = vpd_find_para(pAC,VPD_RW,&rp))) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Encoding Error: RV Tag not found\n"));
-		return (1);
+			("Encoding Error: RV Tag not found\n")) ;
+		return (1) ;
 	}
 	if (r->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Encoding Error: Invalid VPD struct size\n"));
-		return (1);
+			("Encoding Error: Invalid VPD struct size\n")) ;
+		return (1) ;
 	}
-	pAC->vpd.v.vpd_free_rw = r->p_len;
+	pAC->vpd.v.vpd_free_rw = r->p_len ;
 
 	/* everything seems to be ok */
-	pAC->vpd.v.vpd_status |= VPD_VALID;
+	pAC->vpd.v.vpd_status |= VPD_VALID ;
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,
 		("done. Free RO = %d, Free RW = %d\n",
-		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ;
 
-	return(0);
+	return(0) ;
 }
 
 /*
@@ -585,62 +572,62 @@
 SK_VPD_PARA *p)	/* parameter description struct */
 {
 	char *v	;	/* points to vpd buffer */
-	int max;	/* Maximum Number of Iterations */
+	int max ;	/* Maximum Number of Iterations */
 
-	v = pAC->vpd.vpd_buf;
-	max = 128;
+	v = pAC->vpd.vpd_buf ;
+	max = 128 ;
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd find para %s .. ",key));
+		("vpd find para %s .. ",key)) ;
 
 	/* check mandatory resource type ID string (Product Name) */
 	if (*v != (char) RES_ID) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Error: 0x%x missing\n",RES_ID));
-		return (0);
+			("Error: 0x%x missing\n",RES_ID)) ;
+		return (0) ;
 	}
 
 	if (strcmp(key,VPD_NAME) == 0) {
-		p->p_len = VPD_GET_RES_LEN(v);
-		p->p_val = VPD_GET_VAL(v);
+		p->p_len = VPD_GET_RES_LEN(v) ;
+		p->p_val = VPD_GET_VAL(v) ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-			("found, len = %d\n",p->p_len));
-		return(p);
+			("found, len = %d\n",p->p_len)) ;
+		return(p) ;
 	}
 
-	v += 3 + VPD_GET_RES_LEN(v) + 3;
-	for (;; ) {
+	v += 3 + VPD_GET_RES_LEN(v) + 3 ;
+	for ( ; ; ) {
 		if (SK_MEMCMP(key,v,2) == 0) {
-			p->p_len = VPD_GET_VPD_LEN(v);
-			p->p_val = VPD_GET_VAL(v);
+			p->p_len = VPD_GET_VPD_LEN(v) ;
+			p->p_val = VPD_GET_VAL(v) ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-				("found, len = %d\n",p->p_len));
-			return (p);
+				("found, len = %d\n",p->p_len)) ;
+			return (p) ;
 		}
 
 		/* exit when reaching the "RW" Tag or the maximum of itera. */
-		max--;
+		max-- ;
 		if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
-			break;
+			break ;
 		}
 
 		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
-			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
+			v += 3 + VPD_GET_VPD_LEN(v) + 3 ;	/* skip VPD-W */
 		} else {
-			v += 3 + VPD_GET_VPD_LEN(v);
+			v += 3 + VPD_GET_VPD_LEN(v) ;
 		}
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-			("scanning '%c%c' len = %d\n",v[0],v[1],v[2]));
+			("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ;
 	}
 
 #ifdef DEBUG
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n"));
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")) ;
 	if (max == 0) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Key/Len Encoding error\n"));
+			("Key/Len Encoding error\n")) ;
 	}
 #endif
-	return (0);
+	return (0) ;
 }
 
 /*
@@ -654,24 +641,24 @@
 char *end,		/* end of memory block to move */
 int n)			/* number of bytes the memory block has to be moved */
 {
-	char *p;
-	int i;		/* number of byte copied */
+	char *p ;
+	int i ;		/* number of byte copied */
 
 	if (n == 0)
-		return;
+		return ;
 
-	i = (int) (end - start + 1);
+	i = (int) (end - start + 1) ;
 	if (n < 0) {
-		p = start + n;
+		p = start + n ;
 		while (i != 0) {
-			*p++ = *start++;
-			i--;
+			*p++ = *start++ ;
+			i-- ;
 		}
 	} else {
-		p = end + n;
+		p = end + n ;
 		while (i != 0) {
-			*p-- = *end--;
-			i--;
+			*p-- = *end-- ;
+			i-- ;
 		}
 	}
 }
@@ -687,13 +674,13 @@
 int len,		/* length of the value string */
 char *ip)		/* inseration point */
 {
-	SK_VPD_KEY *p;
+	SK_VPD_KEY *p ;
 
-	p = (SK_VPD_KEY *) ip;
-	p->p_key[0] = key[0];
-	p->p_key[1] = key[1];
-	p->p_len = (unsigned char) len;
-	SK_MEMCPY(&p->p_val,buf,len);
+	p = (SK_VPD_KEY *) ip ;
+	p->p_key[0] = key[0] ;
+	p->p_key[1] = key[1] ;
+	p->p_len = (unsigned char) len ;
+	SK_MEMCPY(&p->p_val,buf,len) ;
 }
 
 /*
@@ -707,46 +694,46 @@
 SK_AC *pAC,	/* common data base */
 char *etp)		/* end pointer input position */
 {
-	SK_VPD_KEY *p;
-	unsigned char	x;
-	int	i;
+	SK_VPD_KEY *p ;
+	unsigned char	x ;
+	int	i ;
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
+		("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])) ;
 
-	p = (SK_VPD_KEY *) etp;
+	p = (SK_VPD_KEY *) etp ;
 
 	if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
 		/* something wrong here, encoding error */
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Encoding Error: invalid end tag\n"));
-		return(1);
+			("Encoding Error: invalid end tag\n")) ;
+		return(1) ;
 	}
 	if (etp > pAC->vpd.vpd_buf + VPD_SIZE/2) {
 		/* create "RW" tag */
-		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1);
-		pAC->vpd.v.vpd_free_rw = (int) p->p_len;
-		i = pAC->vpd.v.vpd_free_rw;
-		etp += 3;
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1) ;
+		pAC->vpd.v.vpd_free_rw = (int) p->p_len ;
+		i = pAC->vpd.v.vpd_free_rw ;
+		etp += 3 ;
 	} else {
 		/* create "RV" tag */
-		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3);
-		pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1;
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3) ;
+		pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1 ;
 
 		/* setup checksum */
 		for (i = 0, x = 0; i < VPD_SIZE/2 - p->p_len; i++) {
-			x += pAC->vpd.vpd_buf[i];
+			x += pAC->vpd.vpd_buf[i] ;
 		}
-		p->p_val = (char) 0 - x;
-		i = pAC->vpd.v.vpd_free_ro;
-		etp += 4;
+		p->p_val = (char) 0 - x ;
+		i = pAC->vpd.v.vpd_free_ro ;
+		etp += 4 ;
 	}
 	while (i) {
-		*etp++ = 0x00;
-		i--;
+		*etp++ = 0x00 ;
+		i-- ;
 	}
 
-	return (0);
+	return (0) ;
 }
 
 /*
@@ -771,76 +758,76 @@
 int	type,		/* VPD_RO_KEY or VPD_RW_KEY */
 int	op)			/* operation to do: ADD_KEY or OWR_KEY */
 {
-	SK_VPD_PARA vp;
-	char	*etp;		/* end tag position */
-	int	free;		/* remaining space in selected area */
-	char	*ip;		/* input position inside the VPD buffer */
-	int	rtv;		/* return code */
-	int	head;		/* additional haeder bytes to move */
-	int	found;		/* additinoal bytes if the keyword was found */
+	SK_VPD_PARA vp ;
+	char	*etp ;		/* end tag position */
+	int	free ;		/* remaining space in selected area */
+	char	*ip ;		/* input position inside the VPD buffer */
+	int	rtv ;		/* return code */
+	int	head ;		/* additional haeder bytes to move */
+	int	found ;		/* additinoal bytes if the keyword was found */
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd setup para key = %s, val = %s\n",key,buf));
+		("vpd setup para key = %s, val = %s\n",key,buf)) ;
 
-	rtv = 0;
-	ip = 0;
+	rtv = 0 ;
+	ip = 0 ;
 	if (type == VPD_RW_KEY) {
 		/* end tag is "RW" */
-		free = pAC->vpd.v.vpd_free_rw;
-		etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3);
+		free = pAC->vpd.v.vpd_free_rw ;
+		etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3) ;
 	} else {
 		/* end tag is "RV" */
-		free = pAC->vpd.v.vpd_free_ro;
-		etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4);
+		free = pAC->vpd.v.vpd_free_ro ;
+		etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4) ;
 	}
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
 		("Free RO = %d, Free RW = %d\n",
-		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ;
 
-	head = 0;
-	found = 0;
+	head = 0 ;
+	found = 0 ;
 	if (op == OWR_KEY) {
 		if (vpd_find_para(pAC,key,&vp)) {
-			found = 3;
-			ip = vp.p_val - 3;
-			free += vp.p_len + 3;
+			found = 3 ;
+			ip = vp.p_val - 3 ;
+			free += vp.p_len + 3 ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-				("Overwrite Key\n"));
+				("Overwrite Key\n")) ;
 		} else {
-			op = ADD_KEY;
+			op = ADD_KEY ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-				("Add Key\n"));
+				("Add Key\n")) ;
 		}
 	}
 	if (op == ADD_KEY) {
-		ip = etp;
-		vp.p_len = 0;
-		head = 3;
+		ip = etp ;
+		vp.p_len = 0 ;
+		head = 3 ;
 	}
 
 	if (len + 3 > free) {
 		if (free < 7) {
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
 				("VPD Buffer Overflow, keyword not written\n"));
-			return (4);
+			return (4) ;
 		}
 		/* cut it again */
-		len = free - 3;
-		rtv = 2;
+		len = free - 3 ;
+		rtv = 2 ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("VPD Buffer Full, Keyword was cut\n"));
+			("VPD Buffer Full, Keyword was cut\n")) ;
 	}
 
-	vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head);
-	vpd_insert_key(key, buf, len, ip);
+	vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head) ;
+	vpd_insert_key(key, buf, len, ip) ;
 	if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
-		pAC->vpd.v.vpd_status &= ~VPD_VALID;
+		pAC->vpd.v.vpd_status &= ~VPD_VALID ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("VPD Encoding Error\n"));
-		return(6);
+			("VPD Encoding Error\n")) ;
+		return(6) ;
 	}
 
-	return (rtv);
+	return (rtv) ;
 }
 
 
@@ -848,7 +835,7 @@
  *	Read the contents of the VPD EEPROM and copy it to the
  *	VPD buffer if not already done.
  *
- * return:	A pointer to the vpd_status structure. The structure contains
+ * return:	A pointer to the vpd_status structure. The structure contain
  *		this fields.
  */
 SK_VPD_STATUS	*VpdStat(
@@ -856,9 +843,9 @@
 SK_IOC		IoC)	/* IO Context */
 {
 	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
-		(void)VpdInit(pAC,IoC);
+		(void)VpdInit(pAC,IoC) ;
 	}
-	return(&pAC->vpd.v);
+	return(&pAC->vpd.v) ;
 }
 
 
@@ -891,67 +878,67 @@
 int		*len,		/* buffer length */
 int		*elements)	/* number of keywords returned */
 {
-	char *v;
-	int n;
+	char *v ;
+	int n ;
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. "));
-	*elements = 0;
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")) ;
+	*elements = 0 ;
 	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
 		if (VpdInit(pAC,IoC) != 0 ) {
-			*len = 0;
+			*len = 0 ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("VPD Init Error, terminated\n"));
-			return(6);
+				("VPD Init Error, terminated\n")) ;
+			return(6) ;
 		}
 	}
 
 	if ((signed)strlen(VPD_NAME) + 1 <= *len) {
-		v = pAC->vpd.vpd_buf;
-		strcpy(buf,VPD_NAME);
-		n = strlen(VPD_NAME) + 1;
-		buf += n;
-		*elements = 1;
+		v = pAC->vpd.vpd_buf ;
+		strcpy(buf,VPD_NAME) ;
+		n = strlen(VPD_NAME) + 1 ;
+		buf += n ;
+		*elements = 1 ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
-			("'%c%c' ",v[0],v[1]));
+			("'%c%c' ",v[0],v[1])) ;
 	} else {
-		*len = 0;
+		*len = 0 ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("buffer overflow\n"));
-		return(2);
+			("buffer overflow\n")) ;
+		return(2) ;
 	}
 
-	v += 3 + VPD_GET_RES_LEN(v) + 3;
-	for (;; ) {
+	v += 3 + VPD_GET_RES_LEN(v) + 3 ;
+	for ( ; ; ) {
 		/* exit when reaching the "RW" Tag */
 		if (SK_MEMCMP(VPD_RW,v,2) == 0) {
-			break;
+			break ;
 		}
 
 		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
-			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
-			continue;
+			v += 3 + VPD_GET_VPD_LEN(v) + 3 ;	/* skip VPD-W */
+			continue ;
 		}
 
 		if (n+3 <= *len) {
-			SK_MEMCPY(buf,v,2);
-			buf += 2;
-			*buf++ = '\0';
-			n += 3;
-			v += 3 + VPD_GET_VPD_LEN(v);
-			*elements += 1;
+			SK_MEMCPY(buf,v,2) ;
+			buf += 2 ;
+			*buf++ = '\0' ;
+			n += 3 ;
+			v += 3 + VPD_GET_VPD_LEN(v) ;
+			*elements += 1 ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
-				("'%c%c' ",v[0],v[1]));
+				("'%c%c' ",v[0],v[1])) ;
 		} else {
-			*len = n;
+			*len = n ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("buffer overflow\n"));
-			return (2);
+				("buffer overflow\n")) ;
+			return (2) ;
 		}
 	}
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n"));
-	*len = n;
-	return(0);
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")) ;
+	*len = n ;
+	return(0) ;
 }
 
 
@@ -975,34 +962,34 @@
 char		*buf,	/* buffer where to copy the keyword value */
 int		*len)	/* buffer length */
 {
-	SK_VPD_PARA *p, vp;
+	SK_VPD_PARA *p, vp ;
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key));
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)) ;
 	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
 		if (VpdInit(pAC,IoC) != 0 ) {
-			*len = 0;
+			*len = 0 ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd init error\n"));
-			return(6);
+				("vpd init error\n")) ;
+			return(6) ;
 		}
 	}
 
 	if ((p = vpd_find_para(pAC,key,&vp))) {
 		if (p->p_len > (*(unsigned *)len)-1) {
-			p->p_len = *len - 1;
+			p->p_len = *len - 1 ;
 		}
-		SK_MEMCPY(buf,p->p_val,p->p_len);
-		buf[p->p_len] = '\0';
-		*len = p->p_len;
+		SK_MEMCPY(buf,p->p_val,p->p_len) ;
+		buf[p->p_len] = '\0' ;
+		*len = p->p_len ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
 			("%c%c%c%c.., len = %d\n",
-			buf[0],buf[1],buf[2],buf[3],*len));
+			buf[0],buf[1],buf[2],buf[3],*len)) ;
 	} else {
-		*len = 0;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n"));
-		return (1);
+		*len = 0 ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ;
+		return (1) ;
 	}
-	return (0);
+	return (0) ;
 }
 
 
@@ -1020,9 +1007,9 @@
 		key[1] < '0' || key[1] > 'Z' ||
 		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
 
-		return (SK_FALSE);
+		return (SK_FALSE) ;
 	}
-	return (SK_TRUE);
+	return (SK_TRUE) ;
 }
 
 /*
@@ -1044,46 +1031,46 @@
 char		*key,	/* keyword to write (allowed values "Yx", "Vx") */
 char		*buf)	/* buffer where the keyword value can be read from */
 {
-	int len;			/* lenght of the keyword to write */
-	int rtv;			/* return code */
-	int rtv2;
+	int len ;			/* lenght of the keyword to write */
+	int rtv ;			/* return code */
+	int rtv2 ;
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,
-		("vpd write %s = %s\n",key,buf));
+		("vpd write %s = %s\n",key,buf)) ;
 
 	if ((*key != 'Y' && *key != 'V') ||
 		key[1] < '0' || key[1] > 'Z' ||
 		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
 
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("illegal key tag, keyword not written\n"));
-		return (5);
+			("illegal key tag, keyword not written\n")) ;
+		return (5) ;
 	}
 
 	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
 		if (VpdInit(pAC,IoC) != 0 ) {
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd init error\n"));
-			return(6);
+				("vpd init error\n")) ;
+			return(6) ;
 		}
 	}
 
-	rtv = 0;
-	len = strlen(buf);
+	rtv = 0 ;
+	len = strlen(buf) ;
 	if (len > VPD_MAX_LEN) {
 		/* cut it */
-		len = VPD_MAX_LEN;
-		rtv = 2;
+		len = VPD_MAX_LEN ;
+		rtv = 2 ;
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("keyword to long, cut after %d bytes\n",VPD_MAX_LEN));
+			("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)) ;
 	}
 	if ((rtv2 = VpdSetupPara(pAC,key,buf,len,VPD_RW_KEY,OWR_KEY)) != 0) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("vpd write error\n"));
-		return(rtv2);
+			("vpd write error\n")) ;
+		return(rtv2) ;
 	}
 
-	return (rtv);
+	return (rtv) ;
 }
 
 /*
@@ -1103,15 +1090,15 @@
 SK_IOC		IoC,	/* IO Context */
 char		*key)	/* keyword to read (e.g. "MN") */
 {
-	SK_VPD_PARA *p, vp;
-	char *etp;
+	SK_VPD_PARA *p, vp ;
+	char *etp ;
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key));
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ;
 	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
 		if (VpdInit(pAC,IoC) != 0 ) {
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd init error\n"));
-			return(6);
+				("vpd init error\n")) ;
+			return(6) ;
 		}
 	}
 
@@ -1119,27 +1106,27 @@
 		if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
 			/* try to delete read only keyword */
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("cannot delete RO keyword\n"));
-			return (5);
+				("cannot delete RO keyword\n")) ;
+			return (5) ;
 		}
 
-		etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3);
+		etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3) ;
 
 		vpd_move_para(vp.p_val+vp.p_len, etp+2,
-			- ((int)(vp.p_len + 3)));
+			- ((int)(vp.p_len + 3))) ;
 		if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
-			pAC->vpd.v.vpd_status &= ~VPD_VALID;
+			pAC->vpd.v.vpd_status &= ~VPD_VALID ;
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd encoding error\n"));
-			return(6);
+				("vpd encoding error\n")) ;
+			return(6) ;
 		}
 	} else {
 		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("keyword not found\n"));
-		return (1);
+			("keyword not found\n")) ;
+		return (1) ;
 	}
 
-	return (0);
+	return (0) ;
 }
 
 /*
@@ -1153,18 +1140,18 @@
 SK_AC		*pAC,	/* Adapters context */
 SK_IOC		IoC)	/* IO Context */
 {
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. "));
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ;
 	if (pAC->vpd.v.vpd_status & VPD_VALID) {
 		if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf + VPD_SIZE/2,
 			VPD_SIZE/2, VPD_SIZE/2, VPD_WRITE) != VPD_SIZE/2) {
 
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("transfer timed out\n"));
-			return(3);
+				("transfer timed out\n")) ;
+			return(3) ;
 		}
 	}
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n"));
-	return (0);
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")) ;
+	return (0) ;
 }
 
 
@@ -1184,32 +1171,32 @@
 SK_IOC		IoC,	/* IO Context */
 char		*msg)	/* error log message */
 {
-	SK_VPD_PARA *v, vf;	/* VF */
-	int len;
+	SK_VPD_PARA *v, vf ;	/* VF */
+	int len ;
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,
-		("vpd error log msg %s\n",msg));
+		("vpd error log msg %s\n",msg)) ;
 	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
 		if (VpdInit(pAC,IoC) != 0 ) {
 			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd init error\n"));
-			return;
+				("vpd init error\n")) ;
+			return ;
 		}
 	}
 
-	len = strlen(msg);
+	len = strlen(msg) ;
 	if (len > VPD_MAX_LEN) {
 		/* cut it */
-		len = VPD_MAX_LEN;
+		len = VPD_MAX_LEN ;
 	}
 	if ((v = vpd_find_para(pAC,VPD_VF,&vf))) {
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n"));
-		(void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY);
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")) ;
+		(void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY) ;
 	} else {
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n"));
-		(void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY);
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")) ;
+		(void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY) ;
 	}
 
-	(void)VpdUpdate(pAC,IoC);
+	(void)VpdUpdate(pAC,IoC) ;
 }
 
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c
--- v2.4.6/linux/drivers/net/sk98lin/skxmac2.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/sk98lin/skxmac2.c	Wed Jul  4 11:50:39 2001
@@ -2,16 +2,15 @@
  *
  * Name:	skxmac2.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.53 $
- * Date:	$Date: 2000/07/27 12:22:11 $
+ * Version:	$Revision: 1.61 $
+ * Date:	$Date: 2001/02/09 15:40:59 $
  * Purpose:	Contains functions to initialize the XMAC II
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2001 SysKonnect 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
@@ -27,6 +26,30 @@
  * History:
  *
  *	$Log: skxmac2.c,v $
+ *	Revision 1.61  2001/02/09 15:40:59  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.60  2001/02/07 15:02:01  cgoos
+ *	Added workaround for Fujitsu switch link down.
+ *	
+ *	Revision 1.59  2001/01/10 09:38:06  cgoos
+ *	Fixed Broadcom C0/A1 Id check for workaround.
+ *	
+ *	Revision 1.58  2000/11/29 11:30:38  cgoos
+ *	Changed DEBUG sections with NW output to xDEBUG
+ *	
+ *	Revision 1.57  2000/11/27 12:40:40  rassmann
+ *	Suppressing preamble after first access to BCom, not before (#10556).
+ *	
+ *	Revision 1.56  2000/11/09 12:32:48  rassmann
+ *	Renamed variables.
+ *	
+ *	Revision 1.55  2000/11/09 11:30:10  rassmann
+ *	WA: Waiting after releasing reset until BCom chip is accessible.
+ *	
+ *	Revision 1.54  2000/10/02 14:10:27  rassmann
+ *	Reading BCOM PHY after releasing reset until it returns a valid value.
+ *	
  *	Revision 1.53  2000/07/27 12:22:11  gklug
  *	fix: possible endless loop in XmHardRst.
  *	
@@ -40,10 +63,10 @@
  *	Changed license header to GPL.
  *	
  *	Revision 1.49  1999/11/22 08:12:13  malthoff
- *	Add workaround for power consumption feature of Bcom C0 chip.
+ *	Add workaround for power consumption feature of BCom C0 chip.
  *	
  *	Revision 1.48  1999/11/16 08:39:01  malthoff
- *	Fix: MDIO preamble suppression is port dependend.
+ *	Fix: MDIO preamble suppression is port dependent.
  *	
  *	Revision 1.47  1999/08/27 08:55:35  malthoff
  *	1000BT: Optimizing MDIO transfer by oppressing MDIO preamble.
@@ -79,8 +102,7 @@
  *	Changes for 1000Base-T.
  *	
  *	Revision 1.38  1999/04/08 14:35:10  malthoff
- *	Add code for enabling signal detect. Enabling signal
- *	detect is disabled.
+ *	Add code for enabling signal detect. Enabling signal detect is disabled.
  *	
  *	Revision 1.37  1999/03/12 13:42:54  malthoff
  *	Add: Jumbo Frame Support.
@@ -234,11 +256,11 @@
 /* local variables ************************************************************/
 
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skxmac2.c,v 1.53 2000/07/27 12:22:11 gklug Exp $ (C) SK ";
+	"@(#)$Id: skxmac2.c,v 1.61 2001/02/09 15:40:59 rassmann Exp $ (C) SK ";
 
 /* BCOM PHY magic pattern list */
 typedef struct s_PhyHack {
-	int	PhyReg;		/* Phy register */
+	int		PhyReg;		/* Phy register */
 	SK_U16	PhyVal;		/* Value to write */
 } BCOM_HACK;
 
@@ -278,7 +300,7 @@
  *	 o don't set XMR_FS_ERR in frame	SK_BIG_PK_OK_ON/OFF
  *	   status for frames > 1514 bytes
  *
- *	for incoming packets may be enabled/disabled by this function.
+ *	for incomming packets may be enabled/disabled by this function.
  *	Additional modes may be added later.
  *	Multiple modes can be enabled/disabled at the same time.
  *	The new configuration is stored into the HWAC port configuration
@@ -293,12 +315,12 @@
 void SkXmSetRxCmd(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* The XMAC to handle with belongs to this Port */
-int	Mode)		/* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
-				SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+int		Port,		/* The XMAC to handle with belongs to this Port */
+int		Mode)		/* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+					   SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
 {
-	SK_GEPORT *pPrt;
-	SK_U16	OldRxMode;
+	SK_GEPORT	*pPrt;
+	SK_U16		OldRxMode;
 
 	pPrt = &pAC->GIni.GP[Port];
 	OldRxMode = pPrt->PRxCmd;
@@ -343,7 +365,8 @@
 	if (OldRxMode != pPrt->PRxCmd) {
 		XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
 	}
-}
+}	/* SkXmSetRxCmd*/
+
 
 /******************************************************************************
  *
@@ -360,12 +383,12 @@
 void SkXmClrExactAddr(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* The XMAC to handle with belongs to this Port */
-int	StartNum,	/* Begin with this Address Register Index (0..15) */
-int	StopNum)	/* Stop after finished with this Register Idx (0..15) */
+int		Port,		/* The XMAC to handle with belongs to this Port */
+int		StartNum,	/* Begin with this Address Register Index (0..15) */
+int		StopNum)	/* Stop after finished with this Register Idx (0..15) */
 {
-	int	i;
-	SK_U16	ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 };
+	int		i;
+	SK_U16	ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
 
 	if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
 		StartNum > StopNum) {
@@ -377,7 +400,8 @@
 	for (i = StartNum; i <= StopNum; i++) {
 		XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
 	}
-}
+}	/* SkXmClrExactAddr */
+
 
 /******************************************************************************
  *
@@ -393,12 +417,13 @@
 static void SkXmClrSrcCheck(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+int		Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
 {
-	SK_U16	ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 };
+	SK_U16	ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
 
 	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
-}
+}	/* SkXmClrSrcCheck */
+
 
 /******************************************************************************
  *
@@ -413,12 +438,13 @@
 static void SkXmClrHashAddr(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+int		Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
 {
-	SK_U16	ZeroAddr[4] = { 0x0000, 0x0000, 0x0000, 0x0000 };
+	SK_U16	ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
 
 	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
-}
+}	/* SkXmClrHashAddr*/
+
 
 /******************************************************************************
  *
@@ -433,14 +459,15 @@
 void SkXmFlushTxFifo(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+int		Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
 {
 	SK_U32	MdReg;
 
 	XM_IN32(IoC, Port, XM_MODE, &MdReg);
 	MdReg |= XM_MD_FTF;
 	XM_OUT32(IoC, Port, XM_MODE, MdReg);
-}
+}	/* SkXmFlushTxFifo */
+
 
 /******************************************************************************
  *
@@ -455,14 +482,15 @@
 void SkXmFlushRxFifo(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+int		Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
 {
 	SK_U32	MdReg;
 
 	XM_IN32(IoC, Port, XM_MODE, &MdReg);
 	MdReg |= XM_MD_FRF;
 	XM_OUT32(IoC, Port, XM_MODE, MdReg);
-}
+}	/* SkXmFlushRxFifo*/
+
 
 /******************************************************************************
  *
@@ -502,10 +530,10 @@
 void SkXmSoftRst(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)	/* port to stop (MAC_1 + n) */
+int		Port)	/* port to stop (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16	Word;
+	SK_U16		Word;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -527,13 +555,11 @@
 	
 	/* disable all PHY IRQs */
 	switch (pAC->GIni.GP[Port].PhyType) {
-		case SK_PHY_BCOM:
-			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
-				0xffff);
+	case SK_PHY_BCOM:
+			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 0xffff);
 			break;
 		case SK_PHY_LONE:
-			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
-				0x0);
+			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 0x0);
 			break;
 		case SK_PHY_NAT:
 			/* todo: National
@@ -554,7 +580,8 @@
 	SkXmFlushRxFifo(pAC, IoC, Port);
 
 	pAC->GIni.GP[Port].PState = SK_PRT_STOP;
-}
+}	/* SkXmSoftRst*/
+
 
 /******************************************************************************
  *
@@ -578,18 +605,17 @@
 void SkXmHardRst(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)	/* port to stop (MAC_1 + n) */
+int		Port)	/* port to stop (MAC_1 + n) */
 {
-	SK_U16	Word;
-	int	i;
-	int	TOut;
 	SK_U32	Reg;
+	int		i;
+	int		TOut;
+	SK_U16	Word;
 
-	for (i=0; i<4; i++) {
+	for (i = 0; i < 4; i++) {
 		/* TX_MFF_CTRL1 is a 32 bit register but only the lowest 16 */
 		/* bit contains buttoms to press */
-		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
-			(SK_U16) MFF_CLR_MAC_RST);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), (SK_U16)MFF_CLR_MAC_RST);
 
 		TOut = 0;
 		do {
@@ -610,7 +636,6 @@
 
 	/* For external PHYs there must be special handling */
 	if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
-
 		/* reset external PHY */
 		SK_IN32(IoC, B2_GP_IO, &Reg);
 		if (Port == 0) {
@@ -628,7 +653,8 @@
 	}
 
 	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
-}
+}	/* SkXmHardRst */
+
 
 /******************************************************************************
  *
@@ -639,8 +665,7 @@
  *	The XMAC must be reset or stopped before calling this function.
  *
  * Note:
- *	The XMACs Rx and Tx state machine is still disabled when
- *	returning.
+ *	The XMAC's Rx and Tx state machine is still disabled when returning.
  *
  * Returns:
  *	nothing
@@ -648,12 +673,13 @@
 void SkXmInitMac(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
-	SK_GEPORT *pPrt;
-	SK_U16	SWord;
-	int	i;
-	SK_U32	Reg;
+	SK_GEPORT	*pPrt;
+	SK_U32		Reg;
+	int			i;
+	SK_U16		SWord;
+	SK_U16		PhyId;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -661,79 +687,118 @@
 		/* Port State: SK_PRT_STOP */
 		/* Verify that the reset bit is cleared */
 		SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
-		if (SWord & (SK_U16) MFF_SET_MAC_RST) {
+		if (SWord & (SK_U16)MFF_SET_MAC_RST) {
 			/* PState does not match HW state */
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006,
-				SKERR_HWI_E006MSG);
-			/* correct it */
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+			/* Correct it. */
 			pPrt->PState = SK_PRT_RESET;
 		}
 	}
+
 	if (pPrt->PState == SK_PRT_RESET) {
 		/*
 		 * clear HW reset
 		 * Note: The SW reset is self clearing, therefore there is
 		 *	 nothing to do here.
 		 */
-		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
-			(SK_U16) MFF_CLR_MAC_RST);
-		
-		/*
-		 * clear PHY reset
-		 */
-		if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), (SK_U16)MFF_CLR_MAC_RST);
 
+		/* Ensure that XMAC reset release is done (errata from LReinbold?). */
+		SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+
+		/* Clear PHY reset. */
+		if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
 			SK_IN32(IoC, B2_GP_IO, &Reg);
 			if (Port == 0) {
-				Reg |= GP_DIR_0; /* set to output */
+				Reg |= GP_DIR_0; /* Set to output. */
 				Reg |= GP_IO_0;
 			}
 			else {
-				Reg |= GP_DIR_2; /* set to output */
+				Reg |= GP_DIR_2; /* Set to output. */
 				Reg |= GP_IO_2;
 			}
 			SK_OUT32(IoC, B2_GP_IO, Reg);
 
-			/* enable GMII interface */
+			/* Enable GMII interface. */
 			XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
 
-			/* optimize MDIO transfer by oppressing preamble */
+			PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &PhyId);
+#ifdef xDEBUG
+			if (SWord == 0xFFFF) {
+				i = 1;
+				do {
+					PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &SWord);
+					i++;
+					/* Limit retries; else machine may hang. */
+				} while (SWord == 0xFFFF && i < 500000);
+
+				CMSMPrintString(
+					pAC->pConfigTable,
+					MSG_TYPE_RUNTIME_INFO,
+					"ID1 is %x after %d reads.",
+					(void *)SWord,
+					(void *)i);
+
+				/* Trigger PCI analyzer */
+				/* SK_IN32(IoC, 0x012c, &Reg); */
+			}
+#endif	/* DEBUG */
+
+			/*
+			 * Optimize MDIO transfer by suppressing preamble.
+			 * Must be done AFTER first access to BCOM chip.
+			 */
 			XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
 			XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
 
-			/* Workaround BCOM Errata for the A1 type */
-			/* Write magic patterns to reserved registers */
-			PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &SWord);
-			if (SWord == 0x6041) {
+			if (PhyId == 0x6044) {
+				/* Workaround BCOM Errata for the C0 type. */
+				/* Write magic patterns to reserved registers. */
 				i = 0;
-				while (BcomRegA1Hack[i].PhyReg != 0) {
-					PHY_WRITE(IoC, pPrt, Port,
-						BcomRegA1Hack[i].PhyReg,
-						BcomRegA1Hack[i].PhyVal);
+				while (BcomRegC0Hack[i].PhyReg != 0) {
+					PHY_WRITE(IoC, pPrt, Port, BcomRegC0Hack[i].PhyReg,
+						BcomRegC0Hack[i].PhyVal);
 					i++;
 				}
 			}
-			/* Workaround BCOM Errata for the C0 type */
-			/* Write magic patterns to reserved registers */
-			if (SWord == 0x6044) {
+			else if (PhyId == 0x6041) {
+				/* Workaround BCOM Errata for the A1 type. */
+				/* Write magic patterns to reserved registers. */
 				i = 0;
-				while (BcomRegC0Hack[i].PhyReg != 0) {
-					PHY_WRITE(IoC, pPrt, Port,
-						BcomRegC0Hack[i].PhyReg,
-						BcomRegC0Hack[i].PhyVal);
+				while (BcomRegA1Hack[i].PhyReg != 0) {
+					PHY_WRITE(IoC, pPrt, Port, BcomRegA1Hack[i].PhyReg,
+						BcomRegA1Hack[i].PhyVal);
 					i++;
 				}
 			}
-			/* Workaround BCOM Errata (#10523) for all BCom PHYs*/
-			/* Disable Power Management after reset */
+
+			/* Workaround BCOM Errata (#10523) for all BCom PHYs. */
+			/* Disable Power Management after reset. */
 			PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord);
+#ifdef xDEBUG
+			if (SWord == 0xFFFF) {
+				i = 1;
+				do {
+					PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord);
+					i++;
+					/* Limit retries; else machine may hang. */
+				} while (SWord == 0xFFFF && i < 500000);
+
+				CMSMPrintString(
+					pAC->pConfigTable,
+					MSG_TYPE_RUNTIME_INFO,
+					"AUX_CTRL is %x after %d reads.",
+					(void *)SWord,
+					(void *)i);
+
+				/* Trigger PCI analyzer */
+				/* SK_IN32(IoC, 0x012c, &Reg); */
+			}
+#endif	/* DEBUG */
 			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL,
 				SWord | PHY_B_AC_DIS_PM);
 
-			/*
-			 * PHY LED initialization is performed in
-			 * SkGeXmitLED() (but not here).
-			 */
+			/* PHY LED initialization is done in SkGeXmitLED(), not here. */
 		}
 
 		/* Dummy read the Interrupt source register */
@@ -741,7 +806,7 @@
 		
 		/*
 		 * The autonegotiation process starts immediately after
-		 * clearing the reset. Autonegotiation process should be
+		 * clearing the reset. The autonegotiation process should be
 		 * started by the SIRQ, therefore stop it here immediately.
 		 */
 		SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
@@ -755,8 +820,8 @@
 
 	/*
 	 * configure the XMACs Station Address
-	 * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A
-	 * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B
 	 */
 	for (i = 0; i < 3; i++) {
 		/*
@@ -849,7 +914,8 @@
 	 * This should be done after the autonegotiation process
 	 * has been completed successfully.
 	 */
-}
+}	/* SkXmInitMac*/
+
 
 /******************************************************************************
  *
@@ -866,7 +932,7 @@
 void SkXmInitDupMd(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	switch (pAC->GIni.GP[Port].PLinkModeStatus) {
 	case SK_LMODE_STAT_AUTOHALF:
@@ -895,7 +961,8 @@
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
 		break;
 	}
-}
+}	/* SkXmInitDupMd */
+
 
 /******************************************************************************
  *
@@ -913,11 +980,11 @@
 void SkXmInitPauseMd(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		Word;
 	SK_U32		DWord;
+	SK_U16		Word;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -976,8 +1043,7 @@
 		/* Disable Pause Mode in MAC Rx FIFO */
 		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_DIS_PAUSE);
 	}
-
-}
+}	/* SkXmInitPauseMd*/
 
 
 /******************************************************************************
@@ -995,7 +1061,7 @@
 void SkXmInitPhy(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
 {
 	SK_GEPORT	*pPrt;
@@ -1015,7 +1081,8 @@
 		SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
 		break;
 	}
-}
+}	/* SkXmInitPhy*/
+
 
 /******************************************************************************
  *
@@ -1032,11 +1099,11 @@
 static void SkXmInitPhyXmac(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		Crtl;
+	SK_U16		Ctrl;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -1047,67 +1114,69 @@
 			("InitPhyXmac: no autonegotiation Port %d\n", Port));
 		/* No Autonegiotiation */
 		/* Set DuplexMode in Config register */
-		Crtl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+		Ctrl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
 
 		/*
 		 * Do NOT enable Autonegotiation here. This would hold
 		 * the link down because no IDLES are transmitted
 		 */
-	} else {
+	}
+	else {
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("InitPhyXmac: with autonegotiation Port %d\n", Port));
 		/* Set Autonegotiation advertisement */
-		Crtl = 0;
+		Ctrl = 0;
 
 		/* Set Full/half duplex capabilities */
 		switch (pPrt->PLinkMode) {
 		case SK_LMODE_AUTOHALF:
-			Crtl |= PHY_X_AN_HD;
+			Ctrl |= PHY_X_AN_HD;
 			break;
 		case SK_LMODE_AUTOFULL:
-			Crtl |= PHY_X_AN_FD;
+			Ctrl |= PHY_X_AN_FD;
 			break;
 		case SK_LMODE_AUTOBOTH:
-			Crtl |= PHY_X_AN_FD | PHY_X_AN_HD;
+			Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD;
 			break;
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+				SKERR_HWI_E015, SKERR_HWI_E015MSG);
 		}
 
 		switch (pPrt->PFlowCtrlMode) {
 		case SK_FLOW_MODE_NONE:
-			Crtl |= PHY_X_P_NO_PAUSE;
+			Ctrl |= PHY_X_P_NO_PAUSE;
 			break;
 		case SK_FLOW_MODE_LOC_SEND:
-			Crtl |= PHY_X_P_ASYM_MD;
+			Ctrl |= PHY_X_P_ASYM_MD;
 			break;
 		case SK_FLOW_MODE_SYMMETRIC:
-			Crtl |= PHY_X_P_SYM_MD;
+			Ctrl |= PHY_X_P_SYM_MD;
 			break;
 		case SK_FLOW_MODE_SYM_OR_REM:
-			Crtl |= PHY_X_P_BOTH_MD;
+			Ctrl |= PHY_X_P_BOTH_MD;
 			break;
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E016, SKERR_HWI_E016MSG) ;
+				SKERR_HWI_E016, SKERR_HWI_E016MSG);
 		}
 
 		/* Write AutoNeg Advertisement Register */
-		PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Crtl) ;
+		PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Ctrl);
 
 		/* Restart Autonegotiation */
-		Crtl = PHY_CT_ANE | PHY_CT_RE_CFG;
+		Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
 	}
 
 	if (DoLoop) {
 		/* Set the Phy Loopback bit, too */
-		Crtl |= PHY_CT_LOOP;
+		Ctrl |= PHY_CT_LOOP;
 	}
 
 	/* Write to the Phy control register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Crtl) ;
-}
+	PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Ctrl);
+}	/* SkXmInitPhyXmac*/
+
 
 /******************************************************************************
  *
@@ -1124,23 +1193,29 @@
 static void SkXmInitPhyBcom(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		Crtl1 = PHY_B_CT_SP1000;
-	SK_U16		Crtl2 = 0;
-	SK_U16		Crtl3 = PHY_SEL_TYPE;
-	SK_U16		Crtl4 = PHY_B_PEC_EN_LTR;
-	SK_U16		Crtl5 = PHY_B_AC_TX_TST;
+	SK_U16		Ctrl1;
+	SK_U16		Ctrl2;
+	SK_U16		Ctrl3;
+	SK_U16		Ctrl4;
+	SK_U16		Ctrl5;
+
+	Ctrl1 = PHY_B_CT_SP1000;
+	Ctrl2 = 0;
+	Ctrl3 = PHY_SEL_TYPE;
+	Ctrl4 = PHY_B_PEC_EN_LTR;
+	Ctrl5 = PHY_B_AC_TX_TST;
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	/* manuell Master/Slave ? */
+	/* manually Master/Slave ? */
 	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
-		Crtl2 |= PHY_B_1000C_MSE;
+		Ctrl2 |= PHY_B_1000C_MSE;
 		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
-			Crtl2 |= PHY_B_1000C_MSC;
+			Ctrl2 |= PHY_B_1000C_MSC;
 		}
 	}
 	/* Autonegotiation ? */
@@ -1150,18 +1225,19 @@
 			("InitPhyBcom: no autonegotiation Port %d\n", Port));
 		/* No Autonegiotiation */
 		/* Set DuplexMode in Config register */
-		Crtl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+		Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
 
-		/* Determine Master/Slave manuell if not already done */
+		/* Determine Master/Slave manually if not already done. */
 		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
-			Crtl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+			Ctrl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
 		}
 
 		/*
 		 * Do NOT enable Autonegotiation here. This would hold
 		 * the link down because no IDLES are transmitted
 		 */
-	} else {
+	}
+	else {
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("InitPhyBcom: with autonegotiation Port %d\n", Port));
 		/* Set Autonegotiation advertisement */
@@ -1169,31 +1245,31 @@
 		/* Set Full/half duplex capabilities */
 		switch (pPrt->PLinkMode) {
 		case SK_LMODE_AUTOHALF:
-			Crtl2 |= PHY_B_1000C_AHD;
+			Ctrl2 |= PHY_B_1000C_AHD;
 			break;
 		case SK_LMODE_AUTOFULL:
-			Crtl2 |= PHY_B_1000C_AFD;
+			Ctrl2 |= PHY_B_1000C_AFD;
 			break;
 		case SK_LMODE_AUTOBOTH:
-			Crtl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+			Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
 			break;
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+				SKERR_HWI_E015, SKERR_HWI_E015MSG);
 		}
 
 		switch (pPrt->PFlowCtrlMode) {
 		case SK_FLOW_MODE_NONE:
-			Crtl3 |= PHY_B_P_NO_PAUSE;
+			Ctrl3 |= PHY_B_P_NO_PAUSE;
 			break;
 		case SK_FLOW_MODE_LOC_SEND:
-			Crtl3 |= PHY_B_P_ASYM_MD;
+			Ctrl3 |= PHY_B_P_ASYM_MD;
 			break;
 		case SK_FLOW_MODE_SYMMETRIC:
-			Crtl3 |= PHY_B_P_SYM_MD;
+			Ctrl3 |= PHY_B_P_SYM_MD;
 			break;
 		case SK_FLOW_MODE_SYM_OR_REM:
-			Crtl3 |= PHY_B_P_BOTH_MD;
+			Ctrl3 |= PHY_B_P_BOTH_MD;
 			break;
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
@@ -1201,7 +1277,7 @@
 		}
 
 		/* Restart Autonegotiation */
-		Crtl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+		Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
 
 	}
 	
@@ -1210,39 +1286,40 @@
 	   init order of LEDs and XMAC. (MAl) */
 	
 	/* Write 1000Base-T Control Register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_1000T_CTRL, Crtl2);
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("1000Base-T Control Reg = %x\n", Crtl2));
+		("1000Base-T Control Reg = %x\n", Ctrl2));
 	
 	/* Write AutoNeg Advertisement Register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUNE_ADV, Crtl3);
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("AutoNeg Advertisment Reg = %x\n", Crtl3));
+		("AutoNeg Advertisment Reg = %x\n", Ctrl3));
 	
 
 	if (DoLoop) {
 		/* Set the Phy Loopback bit, too */
-		Crtl1 |= PHY_CT_LOOP;
+		Ctrl1 |= PHY_CT_LOOP;
 	}
 
 	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
 		/* configure fifo to high latency for xmission of ext. packets*/
-		Crtl4 |= PHY_B_PEC_HIGH_LA;
+		Ctrl4 |= PHY_B_PEC_HIGH_LA;
 
 		/* configure reception of extended packets */
-		Crtl5 |= PHY_B_AC_LONG_PACK;
+		Ctrl5 |= PHY_B_AC_LONG_PACK;
 
-		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Crtl5);
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
 	}
 
 	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
-	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Crtl4);
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
 	
 	/* Write to the Phy control register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Crtl1);
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl1);
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("PHY Control Reg = %x\n", Crtl1));
-}
+		("PHY Control Reg = %x\n", Ctrl1));
+}	/* SkXmInitPhyBcom */
+
 
 /******************************************************************************
  *
@@ -1259,21 +1336,25 @@
 static void SkXmInitPhyLone(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		Crtl1 = PHY_L_CT_SP1000;
-	SK_U16		Crtl2 = 0;
-	SK_U16		Crtl3 = PHY_SEL_TYPE;
+	SK_U16		Ctrl1;
+	SK_U16		Ctrl2;
+	SK_U16		Ctrl3;
+
+	Ctrl1 = PHY_L_CT_SP1000;
+	Ctrl2 = 0;
+	Ctrl3 = PHY_SEL_TYPE;
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	/* manuell Master/Slave ? */
+	/* manually Master/Slave ? */
 	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
-		Crtl2 |= PHY_L_1000C_MSE;
+		Ctrl2 |= PHY_L_1000C_MSE;
 		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
-			Crtl2 |= PHY_L_1000C_MSC;
+			Ctrl2 |= PHY_L_1000C_MSC;
 		}
 	}
 	/* Autonegotiation ? */
@@ -1289,18 +1370,19 @@
 			("InitPhyLone: no autonegotiation Port %d\n", Port));
 		/* No Autonegiotiation */
 		/* Set DuplexMode in Config register */
-		Crtl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+		Ctrl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
 
-		/* Determine Master/Slave manuell if not already done */
+		/* Determine Master/Slave manually if not already done. */
 		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
-			Crtl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
+			Ctrl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
 		}
 
 		/*
 		 * Do NOT enable Autonegotiation here. This would hold
 		 * the link down because no IDLES are transmitted
 		 */
-	} else {
+	}
+	else {
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("InitPhyLone: with autonegotiation Port %d\n", Port));
 		/* Set Autonegotiation advertisement */
@@ -1308,31 +1390,31 @@
 		/* Set Full/half duplex capabilities */
 		switch (pPrt->PLinkMode) {
 		case SK_LMODE_AUTOHALF:
-			Crtl2 |= PHY_L_1000C_AHD;
+			Ctrl2 |= PHY_L_1000C_AHD;
 			break;
 		case SK_LMODE_AUTOFULL:
-			Crtl2 |= PHY_L_1000C_AFD;
+			Ctrl2 |= PHY_L_1000C_AFD;
 			break;
 		case SK_LMODE_AUTOBOTH:
-			Crtl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
+			Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
 			break;
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+				SKERR_HWI_E015, SKERR_HWI_E015MSG);
 		}
 
 		switch (pPrt->PFlowCtrlMode) {
 		case SK_FLOW_MODE_NONE:
-			Crtl3 |= PHY_L_P_NO_PAUSE;
+			Ctrl3 |= PHY_L_P_NO_PAUSE;
 			break;
 		case SK_FLOW_MODE_LOC_SEND:
-			Crtl3 |= PHY_L_P_ASYM_MD;
+			Ctrl3 |= PHY_L_P_ASYM_MD;
 			break;
 		case SK_FLOW_MODE_SYMMETRIC:
-			Crtl3 |= PHY_L_P_SYM_MD;
+			Ctrl3 |= PHY_L_P_SYM_MD;
 			break;
 		case SK_FLOW_MODE_SYM_OR_REM:
-			Crtl3 |= PHY_L_P_BOTH_MD;
+			Ctrl3 |= PHY_L_P_BOTH_MD;
 			break;
 		default:
 			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
@@ -1340,7 +1422,7 @@
 		}
 
 		/* Restart Autonegotiation */
-		Crtl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
+		Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
 
 	}
 	
@@ -1349,19 +1431,19 @@
 	   init order of LEDs and XMAC. (MAl) */
 	
 	/* Write 1000Base-T Control Register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_1000T_CTRL, Crtl2);
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_1000T_CTRL, Ctrl2);
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("1000Base-T Control Reg = %x\n", Crtl2));
+		("1000Base-T Control Reg = %x\n", Ctrl2));
 	
 	/* Write AutoNeg Advertisement Register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_AUNE_ADV, Crtl3);
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_AUNE_ADV, Ctrl3);
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("AutoNeg Advertisment Reg = %x\n", Crtl3));
+		("AutoNeg Advertisment Reg = %x\n", Ctrl3));
 	
 
 	if (DoLoop) {
 		/* Set the Phy Loopback bit, too */
-		Crtl1 |= PHY_CT_LOOP;
+		Ctrl1 |= PHY_CT_LOOP;
 	}
 
 	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
@@ -1372,10 +1454,11 @@
 	}
 	
 	/* Write to the Phy control register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Crtl1);
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Ctrl1);
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("PHY Control Reg = %x\n", Crtl1));
-}
+		("PHY Control Reg = %x\n", Ctrl1));
+}	/* SkXmInitPhyLone*/
+
 
 /******************************************************************************
  *
@@ -1392,11 +1475,12 @@
 static void SkXmInitPhyNat(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
 {
 /* todo: National */
-}
+}	/* SkXmInitPhyNat*/
+
 
 /******************************************************************************
  *
@@ -1409,7 +1493,7 @@
 void	SkXmAutoNegLipaXmac(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_U16	IStatus)	/* Interrupt Status word to analyse */
 {
 	SK_GEPORT	*pPrt;
@@ -1423,7 +1507,8 @@
 			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, IStatus));
 		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
 	}
-}
+}	/* SkXmAutoNegLipaXmac*/
+
 
 /******************************************************************************
  *
@@ -1436,21 +1521,20 @@
 void	SkXmAutoNegLipaBcom(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_U16	PhyStat)	/* PHY Status word to analyse */
 {
 	SK_GEPORT	*pPrt;
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
-		(PhyStat & (PHY_ST_AN_OVER))) {
-
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && (PhyStat & PHY_ST_AN_OVER)) {
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
 		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
 	}
-}
+}	/* SkXmAutoNegLipaBcom*/
+
 
 /******************************************************************************
  *
@@ -1477,7 +1561,8 @@
 			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
 		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
 	}
-}
+}	/* SkXmAutoNegLipaLone*/
+
 
 /******************************************************************************
  *
@@ -1490,7 +1575,7 @@
 void	SkXmAutoNegLipaNat(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_U16	PhyStat)	/* PHY Status word to analyse */
 {
 	SK_GEPORT	*pPrt;
@@ -1504,7 +1589,9 @@
 			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
 		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
 	}
-}
+}	/* SkXmAutoNegLipaNat*/
+
+
 /******************************************************************************
  *
  *	SkXmAutoNegDone() - Auto negotiation handling
@@ -1525,13 +1612,9 @@
 int	SkXmAutoNegDone(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
-	SK_GEPORT	*pPrt;
-
-	pPrt = &pAC->GIni.GP[Port];
-
-	switch (pPrt->PhyType) {
+	switch (pAC->GIni.GP[Port].PhyType) {
 	case SK_PHY_XMAC:
 		return (SkXmAutoNegDoneXmac(pAC, IoC, Port));
 	case SK_PHY_BCOM:
@@ -1541,8 +1624,9 @@
 	case SK_PHY_NAT:
 		return (SkXmAutoNegDoneNat(pAC, IoC, Port));
 	}
-	return(SK_AND_OTHER);
-}
+	return (SK_AND_OTHER);
+}	/* SkXmAutoNegDone*/
+
 
 /******************************************************************************
  *
@@ -1562,11 +1646,11 @@
 static int	SkXmAutoNegDoneXmac(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		ResAb ;		/* Resolved Ability */
-	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		LPAb;		/* Link Partner Ability */
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneXmac"
 		"Port %d\n",Port));
@@ -1582,21 +1666,23 @@
 		/* Error */
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("AutoNegFail: Remote fault bit set Port %d\n", Port));
-		pPrt->PAutoNegFail = SK_TRUE ;
-		return (SK_AND_OTHER) ;
+		pPrt->PAutoNegFail = SK_TRUE;
+		return (SK_AND_OTHER);
 	}
 
 	/* Check Duplex mismatch */
 	if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
-		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
-	} else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
-		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
-	} else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF;
+	}
+	else {
 		/* Error */
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
-		pPrt->PAutoNegFail = SK_TRUE ;
-		return (SK_AND_DUP_CAP) ;
+		pPrt->PAutoNegFail = SK_TRUE;
+		return (SK_AND_DUP_CAP);
 	}
 
 	/* Check PAUSE mismatch */
@@ -1607,25 +1693,29 @@
 	    (LPAb & PHY_X_P_SYM_MD)) {
 		/* Symmetric PAUSE */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
-	} else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
+	}
+	else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
 		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
 		/* Enable PAUSE receive, disable PAUSE transmit */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
-	} else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
+	}
+	else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
 		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
 		/* Disable PAUSE receive, enable PAUSE transmit */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
-	} else {
+	}
+	else {
 		/* PAUSE mismatch -> no PAUSE */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 	}
 
 	/* We checked everything and may now enable the link */
-	pPrt->PAutoNegFail = SK_FALSE ;
+	pPrt->PAutoNegFail = SK_FALSE;
 
 	SkXmRxTxEnable(pAC, IoC, Port);
-	return(SK_AND_OK) ;
-}
+	return (SK_AND_OK);
+}	/* SkXmAutoNegDoneXmac*/
+
 
 /******************************************************************************
  *
@@ -1645,82 +1735,99 @@
 static int	SkXmAutoNegDoneBcom(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		ResAb ;		/* Resolved Ability */
-	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		LPAb;		/* Link Partner Ability */
 	SK_U16		AuxStat;	/* Auxiliary Status */
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneBcom,"
-		" Port %d\n",Port));
+#if 0
+01-Sep-2000 RA;:;:
+	SK_U16		ResAb;		/* Resolved Ability */
+#endif	/* 0 */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("AutoNegDoneBcom, Port %d\n", Port));
 	pPrt = &pAC->GIni.GP[Port];
 
-	/* Get PHY parameters */
+	/* Get PHY parameters. */
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LPAb);
+#if 0
+01-Sep-2000 RA;:;:
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+#endif	/* 0 */
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_STAT, &AuxStat);
 
 	if (LPAb & PHY_B_AN_RF) {
-		/* Remote fault bit is set */
-		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		/* Remote fault bit is set: Error. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 			("AutoNegFail: Remote fault bit set Port %d\n", Port));
-		pPrt->PAutoNegFail = SK_TRUE ;
-		return (SK_AND_OTHER) ;
+		pPrt->PAutoNegFail = SK_TRUE;
+		return (SK_AND_OTHER);
 	}
 
-	/* Check Duplex mismatch */
+	/* Check Duplex mismatch. */
 	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000FD) {
-		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
-	} else 	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) {
-		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
-	} else {
-		/* Error */
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF;
+	}
+	else {
+		/* Error. */
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
-		pPrt->PAutoNegFail = SK_TRUE ;
-		return (SK_AND_DUP_CAP) ;
+		pPrt->PAutoNegFail = SK_TRUE;
+		return (SK_AND_DUP_CAP);
 	}
 	
-	/* Check Master/Slave resolution */
-	if (ResAb & (PHY_B_1000S_MSF)) {
-		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+#if 0
+01-Sep-2000 RA;:;:
+	/* Check Master/Slave resolution. */
+	if (ResAb & PHY_B_1000S_MSF) {
+		/* Error. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 			("Master/Slave Fault port %d\n", Port));
 		pPrt->PAutoNegFail = SK_TRUE;
 		pPrt->PMSStatus = SK_MS_STAT_FAULT;
 		return (SK_AND_OTHER);
-	} else if (ResAb & PHY_B_1000S_MSR) {
-		pPrt->PMSStatus = SK_MS_STAT_MASTER ;
-	} else {
-		pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
 	}
+	else if (ResAb & PHY_B_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER;
+	}
+	else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
+	}
+#endif	/* 0 */
 
-	/* Check PAUSE mismatch */
-	/* We are NOT using chapter 4.23 of the Xaqti manual */
-	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	/* Check PAUSE mismatch. */
+	/* We are NOT using chapter 4.23 of the Xaqti manual. */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4. */
 	if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == 
 		(PHY_B_AS_PRR | PHY_B_AS_PRT)) {
-		/* Symmetric PAUSE */
+		/* Symmetric PAUSE. */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
-	} else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRR) {
-		/* Enable PAUSE receive, disable PAUSE transmit */
+	}
+	else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRR) {
+		/* Enable PAUSE receive, disable PAUSE transmit. */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
-	} else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRT) {
-		/* Disable PAUSE receive, enable PAUSE transmit */
+	}
+	else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRT) {
+		/* Disable PAUSE receive, enable PAUSE transmit. */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
-	} else {
-		/* PAUSE mismatch -> no PAUSE */
+	}
+	else {
+		/* PAUSE mismatch -> no PAUSE. */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 	}
 
-	/* We checked everything and may now enable the link */
-	pPrt->PAutoNegFail = SK_FALSE ;
+	/* We checked everything and may now enable the link. */
+	pPrt->PAutoNegFail = SK_FALSE;
 
 	SkXmRxTxEnable(pAC, IoC, Port);
-	return(SK_AND_OK) ;
-}
+	return (SK_AND_OK);
+}	/* SkXmAutoNegDoneBcom*/
+
 
 /******************************************************************************
  *
@@ -1740,11 +1847,11 @@
 static int	SkXmAutoNegDoneLone(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		ResAb ;		/* Resolved Ability */
-	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		LPAb;		/* Link Partner Ability */
 	SK_U16		QuickStat;	/* Auxiliary Status */
 
 	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneLone"
@@ -1761,15 +1868,16 @@
 		/* Error */
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("AutoNegFail: Remote fault bit set Port %d\n", Port));
-		pPrt->PAutoNegFail = SK_TRUE ;
-		return (SK_AND_OTHER) ;
+		pPrt->PAutoNegFail = SK_TRUE;
+		return (SK_AND_OTHER);
 	}
 
 	/* Check Duplex mismatch */
 	if (QuickStat & PHY_L_QS_DUP_MOD) {
-		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
-	} else {
-		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF;
 	}
 	
 	/* Check Master/Slave resolution */
@@ -1778,12 +1886,14 @@
 		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
 			("Master/Slave Fault port %d\n", Port));
 		pPrt->PAutoNegFail = SK_TRUE;
-		pPrt->PMSStatus = SK_MS_STAT_FAULT ;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
 		return (SK_AND_OTHER);
-	} else if (ResAb & PHY_L_1000S_MSR) {
-		pPrt->PMSStatus = SK_MS_STAT_MASTER ;
-	} else {
-		pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
+	}
+	else if (ResAb & PHY_L_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER;
+	}
+	else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
 	}
 
 	/* Check PAUSE mismatch */
@@ -1825,11 +1935,12 @@
 	}
 
 	/* We checked everything and may now enable the link */
-	pPrt->PAutoNegFail = SK_FALSE ;
+	pPrt->PAutoNegFail = SK_FALSE;
 
 	SkXmRxTxEnable(pAC, IoC, Port);
-	return(SK_AND_OK);
-}
+	return (SK_AND_OK);
+}	/* SkXmAutoNegDoneLone */
+
 
 /******************************************************************************
  *
@@ -1851,11 +1962,12 @@
 static int	SkXmAutoNegDoneNat(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 /* todo: National */
-	return(SK_AND_OK);
-}
+	return (SK_AND_OK);
+}	/* SkXmAutoNegDoneNat*/
+
 
 /******************************************************************************
  *
@@ -1873,10 +1985,10 @@
 int SkXmRxTxEnable(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port)		/* Port Index (MAC_1 + n) */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		Reg ;		/* 16bit register value */
+	SK_U16		Reg;		/* 16bit register value */
 	SK_U16		IntMask;	/* XMac interrupt mask */
 	SK_U16		SWord;
 
@@ -1884,7 +1996,7 @@
 
 	if (!pPrt->PHWLinkUp) {
 		/* The Hardware link is NOT up */
-		return(0) ;
+		return (0);
 	}
 
 	if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
@@ -1892,7 +2004,7 @@
 	     pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
 	     pPrt->PAutoNegFail) {
 		/* Autonegotiation is not done or failed */
-		return(0) ;
+		return (0);
 	}
 
 	/* Set Dup Mode and Pause Mode */
@@ -1929,14 +2041,11 @@
 		/* Workaround BCOM Errata (#10523) for all BCom Phys */
 		/* Enable Power Management after link up */
 		PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord);
-		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL,	
-			SWord & ~PHY_B_AC_DIS_PM);
-		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
-			PHY_B_DEF_MSK);
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, SWord & ~PHY_B_AC_DIS_PM);
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
 		break;
 	case SK_PHY_LONE:
-		PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
-			PHY_L_DEF_MSK);
+		PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
 		break;
 	case SK_PHY_NAT:
 		/* todo National:
@@ -1948,9 +2057,10 @@
 	XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
 				      
 	return (0);
-}
+}	/* SkXmRxTxEnable*/
 
 #ifndef SK_DIAG
+
 /******************************************************************************
  *
  *	SkXmIrq() - Interrupt service routine
@@ -1976,11 +2086,12 @@
 void SkXmIrq(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
+int		Port,		/* Port Index (MAC_1 + n) */
 SK_U16	IStatus)	/* Interrupt status read from the XMAC */
 {
 	SK_GEPORT	*pPrt;
 	SK_EVPARA	Para;
+	SK_U16		IStatus2;
 
 	pPrt = &pAC->GIni.GP[Port];
 	
@@ -1992,7 +2103,7 @@
 	}
 	
 	/*
-	 * LinkPartner Autonegable ?
+	 * LinkPartner Autonegable?
 	 */
 	if (pPrt->PhyType == SK_PHY_XMAC) {
 		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
@@ -2004,11 +2115,22 @@
 	if (!pPrt->PHWLinkUp) {
 		/* Spurious XMAC interrupt */
 		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
-			("SkXmIrq: spurious interrupt on port %d\n",
-			 Port));
+			("SkXmIrq: spurious interrupt on port %d\n", Port));
 		return;
 	}
 
+	if (IStatus & XM_IS_INP_ASS) {
+		/* Reread ISR Register if link is not in sync */
+		XM_IN16(IoC, Port, XM_ISRC, &IStatus2);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: Link async. Double check port %d %x %x\n",
+			 Port, IStatus, IStatus2));
+		IStatus &= ~XM_IS_INP_ASS;
+		IStatus |= IStatus2;
+
+	}
+
 	if (IStatus & XM_IS_LNK_AE) {
 		/* not used GP0 is used instead */
 	}
@@ -2030,7 +2152,7 @@
 
 		/* Start workaround Errata #2 timer */
 		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
-			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+			SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para);
 	}
 
 	if (IStatus & XM_IS_RX_PAGE) {
@@ -2069,7 +2191,7 @@
 	if (IStatus & XM_IS_TXF_UR) {
 		/* may NOT happen -> error log */
 		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E020,
-			SKERR_SIRQ_E020MSG) ;
+			SKERR_SIRQ_E020MSG);
 	}
 
 	if (IStatus & XM_IS_TX_COMP) {
@@ -2080,7 +2202,8 @@
 		/* not served here */
 	}
 
-}
+}	/* SkXmIrq*/
+
 #endif /* !SK_DIAG */
 
 /* End of file */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.4.6/linux/drivers/net/sk_g16.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/sk_g16.c	Wed Jul  4 11:50:39 2001
@@ -542,12 +542,13 @@
 {
 	int ioaddr;			   /* I/O port address used for POS regs */
 	int *port, ports[] = SK_IO_PORTS;  /* SK_G16 supported ports */
+	static unsigned version_printed;
 
 	/* get preconfigured base_addr from dev which is done in Space.c */
 	int base_addr = dev->base_addr; 
 
-        PRINTK(("%s: %s", SK_NAME, rcsid));
-        rcsid = NULL;                 /* We do not want to use this further */
+	if (version_printed++ == 0)
+	        PRINTK(("%s: %s", SK_NAME, rcsid));
 
 	if (base_addr > 0x0ff)        /* Check a single specified address */
 	{
@@ -2078,7 +2079,7 @@
  *     YY/MM/DD  uid  Description
 -*/
 
-void SK_print_ram(struct net_device *dev)
+void __init SK_print_ram(struct net_device *dev)
 {
 
     int i;    
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
--- v2.4.6/linux/drivers/net/sk_mca.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/sk_mca.c	Wed Jul  4 11:50:39 2001
@@ -91,6 +91,7 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/mca.h>
+#include <linux/init.h>
 #include <asm/processor.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -151,7 +152,7 @@
 
 /* deduce resources out of POS registers */
 
-static void getaddrs(int slot, int junior, int *base, int *irq,
+static void __init getaddrs(int slot, int junior, int *base, int *irq,
 		     skmca_medium * medium)
 {
 	u_char pos0, pos1, pos2;
@@ -197,7 +198,7 @@
    is disabled and won't get detected using the standard probe.  We
    therefore have to scan the slots manually :-( */
 
-static int dofind(int *junior, int firstslot)
+static int __init dofind(int *junior, int firstslot)
 {
 	int slot;
 	unsigned int id;
@@ -524,7 +525,7 @@
 
 /* probe for device's irq */
 
-static int ProbeIRQ(struct SKMCA_NETDEV *dev)
+static int __init ProbeIRQ(struct SKMCA_NETDEV *dev)
 {
 	unsigned long imaskval, njiffies, irq;
 	u16 csr0val;
@@ -1072,7 +1073,7 @@
 
 static int startslot;		/* counts through slots when probing multiple devices */
 
-int skmca_probe(struct SKMCA_NETDEV *dev)
+int __init skmca_probe(struct SKMCA_NETDEV *dev)
 {
 	int force_detect = 0;
 	int junior, slot, i;
@@ -1250,8 +1251,8 @@
 };
 #endif
 
-int irq = 0;
-int io = 0;
+int irq;
+int io;
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.4.6/linux/drivers/net/skfp/ess.c linux/drivers/net/skfp/ess.c
--- v2.4.6/linux/drivers/net/skfp/ess.c	Wed Jul  5 10:56:13 2000
+++ linux/drivers/net/skfp/ess.c	Wed Jul  4 11:50:39 2001
@@ -258,8 +258,16 @@
 		 * Extract message parameters
 		 */
 		p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+                if (!p) {
+                        printk(KERN_ERR "ESS: sm_to_para failed");
+                        return fs;
+                }       
 		payload = ((struct smt_p_320f *)p)->mib_payload ;
 		p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+                if (!p) {
+                        printk(KERN_ERR "ESS: sm_to_para failed");
+                        return fs;
+                }       
 		overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
 
 		DB_ESSN(2,"payload= %lx	overhead= %lx\n",payload,overhead) ;
diff -u --recursive --new-file v2.4.6/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.4.6/linux/drivers/net/sun3lance.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/sun3lance.c	Wed Jul  4 11:50:39 2001
@@ -881,7 +881,7 @@
 
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
+static char devicename[9];
 
 static struct net_device sun3lance_dev =
 {
diff -u --recursive --new-file v2.4.6/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.4.6/linux/drivers/net/tokenring/ibmtr.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/tokenring/ibmtr.c	Wed Jul  4 11:50:39 2001
@@ -10,7 +10,8 @@
  *	I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work
  *	as a base for most of my initial work.
  *
- *	Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
+ *	Changes by Peter De Schrijver
+ *		(Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
  *
  *	+ changed name to ibmtr.c in anticipation of other tr boards.
  *	+ changed reset code and adapter open code.
@@ -47,6 +48,7 @@
  *	+ added -DPCMCIA to support PCMCIA
  *	+ detecting PCMCIA Card Removal in interrupt handler.  If
  *	  ISRP is FF, then a PCMCIA card has been removed
+ *        10/2000 Burt needed a new method to avoid crashing the OS
  *
  *	Changes by Paul Norton (pnorton@cts.com) :
  *	+ restructured the READ.LOG logic to prevent the transmit SRB
@@ -83,7 +85,7 @@
  *      Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting
  *      i.e. using functional address C0 00 00 04 00 00 to transmit and 
  *      receive multicast packets.
- * 
+ *
  *      Changes by Mike Sullivan (based on original sram patch by Dave Grothe
  *      to support windowing into on adapter shared ram.
  *      i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging
@@ -91,6 +93,13 @@
  *
  *      Changes by Peter De Schrijver (p2@mind.be) :
  *      + fixed a problem with PCMCIA card removal
+ *
+ *      Change by Mike Sullivan et al.:
+ *      + added turbo card support. No need to use lanaid to configure
+ *      the adapter into isa compatiblity mode.
+ *
+ *      Changes by Burt Silverman to allow the computer to behave nicely when
+ *	a cable is pulled or not in place, or a PCMCIA card is removed hot.
  */
 
 /* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value 
@@ -100,207 +109,247 @@
 
 #include <linux/module.h>
 
-#define NO_AUTODETECT 1
-#undef NO_AUTODETECT
-/* #undef ENABLE_PAGING */
-#define ENABLE_PAGING 1
-
+#ifdef PCMCIA
+#undef MODULE
+#undef ENABLE_PAGING
+#else
+#define ENABLE_PAGING 1		
+#endif
 
 #define FALSE 0
 #define TRUE (!FALSE)
 
-/* changes the output format of driver initialisation */
-#define TR_NEWFORMAT	1
+/* changes the output format of driver initialization */
 #define TR_VERBOSE	0
 
 /* some 95 OS send many non UI frame; this allow removing the warning */
 #define TR_FILTERNONUI	1
 
-/* version and credits */
-static char *version =
-"ibmtr.c: v1.3.57   8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-"         v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n"
-"         v2.2.0   12/30/98 Joel Sloan <jjs@c-me.com>\n"
-"         v2.2.1   02/08/00 Mike Sullivan <sullivam@us.ibm.com>\n";
-
-static char pcchannelid[] = {
-	0x05, 0x00, 0x04, 0x09,
-	0x04, 0x03, 0x04, 0x0f,
-	0x03, 0x06, 0x03, 0x01,
-	0x03, 0x01, 0x03, 0x00,
-	0x03, 0x09, 0x03, 0x09,
-	0x03, 0x00, 0x02, 0x00
-};
-
-static char mcchannelid[] = {
-	0x04, 0x0d, 0x04, 0x01,
-	0x05, 0x02, 0x05, 0x03,
-	0x03, 0x06, 0x03, 0x03,
-	0x05, 0x08, 0x03, 0x04,
-	0x03, 0x05, 0x03, 0x01,
-	0x03, 0x08, 0x02, 0x00
-};
-
-#include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/in.h>
 #include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
 #include <linux/ibmtr.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-
 
 #define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
 #define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)
 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
 
-#if TR_NEWFORMAT
+/* version and credits */
+#ifndef PCMCIA
+static char version[] __initdata =
+    "\nibmtr.c: v1.3.57   8/ 7/94 Peter De Schrijver and Mark Swanson\n"
+    "         v2.1.125 10/20/98 Paul Norton    <pnorton@ieee.org>\n"
+    "         v2.2.0   12/30/98 Joel Sloan     <jjs@c-me.com>\n"
+    "         v2.2.1   02/08/00 Mike Sullivan  <sullivam@us.ibm.com>\n" 
+    "         v2.2.2   07/27/00 Burt Silverman <burts@us.ibm.com>\n" 
+    "         v2.4.0   03/01/01 Mike Sullivan <sullivan@us.ibm.com>\n";
+#endif
+
 /* this allows displaying full adapter information */
 
-const char *channel_def[] __initdata = { 
-	"ISA", "MCA", "ISA P&P" 
+char *channel_def[] __initdata = { "ISA", "MCA", "ISA P&P" };
+
+static char pcchannelid[] __devinitdata = {
+	0x05, 0x00, 0x04, 0x09,
+	0x04, 0x03, 0x04, 0x0f,
+	0x03, 0x06, 0x03, 0x01,
+	0x03, 0x01, 0x03, 0x00,
+	0x03, 0x09, 0x03, 0x09,
+	0x03, 0x00, 0x02, 0x00
+};
+
+static char mcchannelid[] __devinitdata =  {
+	0x04, 0x0d, 0x04, 0x01,
+	0x05, 0x02, 0x05, 0x03,
+	0x03, 0x06, 0x03, 0x03,
+	0x05, 0x08, 0x03, 0x04,
+	0x03, 0x05, 0x03, 0x01,
+	0x03, 0x08, 0x02, 0x00
 };
 
-char __init *adapter_def(char type)
+char __devinit *adapter_def(char type)
 {
-	switch (type) 
-	{
-	      case 0xF : return "PC Adapter | PC Adapter II | Adapter/A";
-	      case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)";
-	      case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
-	      case 0xC : return "Auto 16/4 Adapter";
-	      default  : return "adapter (unknown type)";
+	switch (type) {
+	case 0xF: return "PC Adapter | PC Adapter II | Adapter/A";
+	case 0xE: return "16/4 Adapter | 16/4 Adapter/A (long)";
+	case 0xD: return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
+	case 0xC: return "Auto 16/4 Adapter";
+	default: return "adapter (unknown type)";
 	};
 };
-#endif
 
-#if !TR_NEWFORMAT
-unsigned char ibmtr_debug_trace=1;  /*  Patch or otherwise alter to
-                                         control tokenring tracing.  */
-#else
-unsigned char ibmtr_debug_trace=0;
-#endif
-#define TRC_INIT 0x01              /*  Trace initialization & PROBEs */
-#define TRC_INITV 0x02             /*  verbose init trace points     */
+#define TRC_INIT 0x01		/*  Trace initialization & PROBEs */
+#define TRC_INITV 0x02		/*  verbose init trace points     */
+unsigned char ibmtr_debug_trace = 0;
 
-int		ibmtr_probe(struct net_device *dev);
+int 		ibmtr_probe(struct net_device *dev);
 static int	ibmtr_probe1(struct net_device *dev, int ioaddr);
-static unsigned char	get_sram_size(struct tok_info *adapt_info);
-#ifdef PCMCIA
-extern unsigned char 	pcmcia_reality_check(unsigned char gss);
-#endif
-static int	tok_init_card(struct net_device *dev);
-void		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int	trdev_init(struct net_device *dev);
+static unsigned char get_sram_size(struct tok_info *adapt_info);
+static int 	trdev_init(struct net_device *dev);
+static int 	tok_open(struct net_device *dev);
+static int 	tok_init_card(struct net_device *dev);
+void 		tok_open_adapter(unsigned long dev_addr);
+static void 	open_sap(unsigned char type, struct net_device *dev);
+static void 	tok_set_multicast_list(struct net_device *dev);
+static int 	tok_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int 	tok_close(struct net_device *dev);
+void 		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void 	initial_tok_int(struct net_device *dev);
-static void 	open_sap(unsigned char type,struct net_device *dev);
-void		tok_open_adapter(unsigned long dev_addr);
-static		void tr_rx(struct net_device *dev);
-static		void tr_tx(struct net_device *dev);
-static int	tok_open(struct net_device *dev);
-static int	tok_close(struct net_device *dev);
-static int	tok_send_packet(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats * tok_get_stats(struct net_device *dev);
-static void	tok_set_multicast_list(struct net_device *dev);
-void		ibmtr_readlog(struct net_device *dev);
-void		ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev);
-int             ibmtr_change_mtu(struct net_device *dev, int mtu);
+static void 	tr_tx(struct net_device *dev);
+static void 	tr_rx(struct net_device *dev);
+void 		ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev);
+static void	tok_rerun(unsigned long dev_addr);
+void 		ibmtr_readlog(struct net_device *dev);
+static struct 	net_device_stats *tok_get_stats(struct net_device *dev);
+int 		ibmtr_change_mtu(struct net_device *dev, int mtu);
+static void	find_turbo_adapters(int *iolist);
 
-static unsigned int ibmtr_portlist[] __initdata = {
-	0xa20, 0xa24, 0
+static int ibmtr_portlist[IBMTR_MAX_ADAPTERS+1] __devinitdata = {
+	0xa20, 0xa24, 0, 0, 0
 };
+static int __devinitdata turbo_io[IBMTR_MAX_ADAPTERS] = {0};
+static int __devinitdata turbo_irq[IBMTR_MAX_ADAPTERS] = {0};
+static int __devinitdata turbo_searched = 0;
 
-static __u32 ibmtr_mem_base = 0xd0000;
+#ifndef PCMCIA
+static __u32 ibmtr_mem_base __initdata = 0xd0000;
+#endif
 
-static void __init PrtChanID(char *pcid, short stride) 
+static void __devinit PrtChanID(char *pcid, short stride)
 {
 	short i, j;
-	for (i=0, j=0; i<24; i++, j+=stride)
+	for (i = 0, j = 0; i < 24; i++, j += stride)
 		printk("%1x", ((int) pcid[j]) & 0x0f);
 	printk("\n");
 }
 
-static void __init HWPrtChanID (__u32 pcid, short stride)
+static void __devinit HWPrtChanID(__u32 pcid, short stride)
 {
 	short i, j;
-	for (i=0, j=0; i<24; i++, j+=stride)
-		printk("%1x", ((int)isa_readb(pcid + j)) & 0x0f);
+	for (i = 0, j = 0; i < 24; i++, j += stride)
+		printk("%1x", ((int) readb(pcid + j)) & 0x0f);
 	printk("\n");
 }
 
-/*
+static void __devinit find_turbo_adapters(int *iolist) {
+	int ram_addr;
+	int index=0;
+	__u32 chanid;
+	int found_turbo=0;
+	unsigned char *tchanid, ctemp;
+	int i,j;
+  
+	if (turbo_searched == 1) return;
+	turbo_searched=1;
+	for (ram_addr=0xC0000; ram_addr < 0xE0000; ram_addr+=0x2000) {
+
+		__u32 intf_tbl=0;
+
+		found_turbo=1;
+		chanid=(CHANNEL_ID + ram_addr);
+		tchanid=pcchannelid;
+		ctemp=isa_readb(chanid) & 0x0f;
+		if (ctemp != *tchanid) continue;
+		for (i=2,j=1; i<=46; i=i+2,j++) {
+			if ((isa_readb(chanid+i) & 0x0f) != tchanid[j]){
+				found_turbo=0;
+				break;
+			}
+		}
+		if (!found_turbo) continue;
+
+		isa_writeb(0x90, ram_addr+0x1E01);
+		for(i=2; i<0x0f; i++) {
+			isa_writeb(0x00, ram_addr+0x1E01+i);
+		}
+		isa_writeb(0x00, ram_addr+0x1E01);
+		for(i=jiffies+TR_BUSY_INTERVAL; time_before_eq(jiffies,i););
+		intf_tbl=ntohs(isa_readw(ram_addr+ACA_OFFSET+ACA_RW+WRBR_EVEN));
+		if (intf_tbl) {
+#if IBMTR_DEBUG_MESSAGES
+			printk("ibmtr::find_turbo_adapters, Turbo found at "
+				"ram_addr %x\n",ram_addr);
+			printk("ibmtr::find_turbo_adapters, interface_table ");
+			for(i=0; i<6; i++) {
+				printk("%x:",isa_readb(ram_addr+intf_tbl+i));
+			}
+			printk("\n");
+#endif
+			turbo_io[index]=ntohs(isa_readw(ram_addr+intf_tbl+4));
+			turbo_irq[index]=isa_readb(ram_addr+intf_tbl+3);
+			outb(0, turbo_io[index] + ADAPTRESET);
+			for(i=jiffies+TR_RST_TIME;time_before_eq(jiffies,i););
+			outb(0, turbo_io[index] + ADAPTRESETREL);
+			index++;
+			continue;
+		}
+#if IBMTR_DEBUG_MESSAGES 
+		printk("ibmtr::find_turbo_adapters, ibmtr card found at"
+			" %x but not a Turbo model\n",ram_addr);
+#endif
+	}
+	for(i=0; i<IBMTR_MAX_ADAPTERS; i++) {
+		if(!turbo_io[i]) break;
+		for (j=0; j<IBMTR_MAX_ADAPTERS; j++) {
+			if ( iolist[j] && iolist[j] != turbo_io[i]) continue;
+			iolist[j]=turbo_io[i];
+			break;
+		}
+	}
+}
+
+/****************************************************************************
  *	ibmtr_probe():  Routine specified in the network device structure
  *	to probe for an IBM Token Ring Adapter.  Routine outline:
  *	I.    Interrogate hardware to determine if an adapter exists
  *	      and what the speeds and feeds are
  *	II.   Setup data structures to control execution based upon
  *	      adapter characteristics.
- *	III.  Initialize adapter operation
  *
  *	We expect ibmtr_probe to be called once for each device entry
  *	which references it.
- *
- *	Argument 'dev' should never be NULL.  If we are built into
- *	the kernel, Space.c passed up a net_device.  If we are
- *	-DMODULE, init_module allocates net_devices for us.
- */
- 
-int __init ibmtr_probe(struct net_device *dev)
+ ****************************************************************************/
+
+int __devinit ibmtr_probe(struct net_device *dev)
 {
-        int i;
-        int base_addr = dev->base_addr;
+	int i;
+	int base_addr = dev->base_addr;
 
-        if (base_addr > 0x1ff) 
-        { 
-        	/*
-        	 *	Check a single specified location. 
- 		 */
- 		 
-	        if (ibmtr_probe1(dev, base_addr)) 
-		       return -ENODEV;
-		else
-		       return 0;
+	if (base_addr && base_addr <= 0x1ff) /* Don't probe at all. */
+		return -ENXIO;
+	if (base_addr > 0x1ff) { /* Check a single specified location.  */
+		if (!ibmtr_probe1(dev, base_addr)) return 0;
+		return -ENODEV;
 	}
-        else if (base_addr != 0)   /* Don't probe at all. */
-	        return -ENXIO;
-
-	for (i = 0; ibmtr_portlist[i]; i++) 
-	{
-	        int ioaddr = ibmtr_portlist[i];
-		if (check_region(ioaddr, IBMTR_IO_EXTENT))
-		        continue;
-		if (!ibmtr_probe1(dev, ioaddr))
-			return 0;
-        }
+	find_turbo_adapters(ibmtr_portlist);
+	for (i = 0; ibmtr_portlist[i]; i++) {
+		int ioaddr = ibmtr_portlist[i];
 
-        return -ENODEV;
+		if (check_region(ioaddr, IBMTR_IO_EXTENT)) continue;
+		if (!ibmtr_probe1(dev, ioaddr)) return 0;
+	}
+	return -ENODEV;
 }
 
-static int __init ibmtr_probe1(struct net_device *dev, int PIOaddr)
+/*****************************************************************************/
+
+static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
 {
-	unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0;
-	__u32 t_mmio=0;
-	struct tok_info *ti=0;
+
+	unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
+	__u32 t_mmio = 0;
+	struct tok_info *ti = 0;
 	__u32 cd_chanid;
 	unsigned char *tchanid, ctemp;
 #ifndef PCMCIA
-	unsigned long timeout;
+	unsigned char t_irq=0;
+        unsigned long timeout;
+	static int version_printed;
 #endif
 
 #ifndef MODULE
@@ -309,466 +358,414 @@
 #endif
 #endif
 
-	/*	Query the adapter PIO base port which will return
-	 *	indication of where MMIO was placed. We also have a
-	 *	coded interrupt number.
-	 */
-
-       	segment = inb(PIOaddr);
-
-	/*
-	 *	Out of range values so we'll assume non-existent IO device 
+	/*    Query the adapter PIO base port which will return
+	 *    indication of where MMIO was placed. We also have a
+	 *    coded interrupt number.
 	 */
-	 
-	if (segment < 0x40 || segment > 0xe0)
-                return -ENODEV;
-
+	segment = inb(PIOaddr);
+	if (segment < 0x40 || segment > 0xe0) {
+		/* Out of range values so we'll assume non-existent IO device
+		 * but this is not necessarily a problem, esp if a turbo
+		 * adapter is being used.  */
+#if IBMTR_DEBUG_MESSAGES
+		DPRINTK("ibmtr_probe1(): unhappy that inb(0x%X) == 0x%X, "
+			"Hardware Problem?\n",PIOaddr,segment);
+#endif
+		return -ENODEV;
+	}
 	/*
-	 *	Compute the linear base address of the MMIO area
-	 *	as LINUX doesn't care about segments
+	 *    Compute the linear base address of the MMIO area
+	 *    as LINUX doesn't care about segments
 	 */
-
-	t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000);
-	intr = segment & 0x03;   /* low bits is coded interrupt # */
+	t_mmio = (u32)ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
+	if (!t_mmio) { 
+		DPRINTK("Cannot remap mmiobase memory area") ; 
+		return -ENODEV ; 
+	} 
+	intr = segment & 0x03;	/* low bits is coded interrupt # */
 	if (ibmtr_debug_trace & TRC_INIT)
-		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n",
-                         PIOaddr, (int)segment, t_mmio, (int)intr);
-
-	/*
-	 *	Now we will compare expected 'channelid' strings with
-	 *	what we is there to learn of ISA/MCA or not TR card
-	 */
-	 
-	cd_chanid = (CHANNEL_ID + t_mmio);  /* for efficiency */
-	tchanid=pcchannelid;
-	cardpresent=TR_ISA;  /* try ISA */
+		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n"
+				, PIOaddr, (int) segment, t_mmio, (int) intr);
 
 	/*
-	 *	Suboptimize knowing first byte different
+	 *    Now we will compare expected 'channelid' strings with
+	 *    what we is there to learn of ISA/MCA or not TR card
 	 */
-
-	ctemp = isa_readb(cd_chanid) & 0x0f;
-	if (ctemp != *tchanid) { /* NOT ISA card, try MCA */
-		tchanid=mcchannelid;
-		cardpresent=TR_MCA;
-		if (ctemp != *tchanid)  /* Neither ISA nor MCA */
-			cardpresent=NOTOK;
-	}
-
-	if (cardpresent != NOTOK) 
-	{
-		/* 
-		 *	Know presumed type, try rest of ID 
-		 */
-		for (i=2,j=1; i<=46; i=i+2,j++) 
-		{
-			if ((isa_readb(cd_chanid+i) & 0x0f) != tchanid[j]) {
-				cardpresent=NOTOK;   /* match failed, not TR card */
-				break;
-			}
+#ifdef PCMCIA
+	ti = dev->priv;		/*BMS moved up here */
+	t_mmio = ti->mmio;	/*BMS to get virtual address */
+	irq = ti->irq;		/*BMS to display the irq!   */
+#endif
+	cd_chanid = (CHANNEL_ID + t_mmio);	/* for efficiency */
+	tchanid = pcchannelid;
+	cardpresent = TR_ISA;	/* try ISA */
+
+	/*    Suboptimize knowing first byte different */
+	ctemp = readb(cd_chanid) & 0x0f;
+	if (ctemp != *tchanid) {	/* NOT ISA card, try MCA */
+		tchanid = mcchannelid;
+		cardpresent = TR_MCA;
+		if (ctemp != *tchanid)	/* Neither ISA nor MCA */
+			cardpresent = NOTOK;
+	}
+	if (cardpresent != NOTOK) {
+		/*       Know presumed type, try rest of ID */
+		for (i = 2, j = 1; i <= 46; i = i + 2, j++) {
+			if( (readb(cd_chanid+i)&0x0f) == tchanid[j]) continue;
+			/* match failed, not TR card */
+			cardpresent = NOTOK;
+			break;
 		}
 	}
-
 	/* 
-	 *	If we have an ISA board check for the ISA P&P version,
-	 *	as it has different IRQ settings 
+	 *    If we have an ISA board check for the ISA P&P version,
+	 *    as it has different IRQ settings 
 	 */
-
-	if (cardpresent == TR_ISA && (isa_readb(AIPFID + t_mmio)==0x0e))
-	        cardpresent=TR_ISAPNP;
-
-	if (cardpresent == NOTOK) { /* "channel_id" did not match, report */
-		if (ibmtr_debug_trace & TRC_INIT) {
-			DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr);
-			DPRINTK("Expected for ISA: ");  PrtChanID(pcchannelid,1);
-			DPRINTK("           found: ");  HWPrtChanID(cd_chanid,2);
-			DPRINTK("Expected for MCA: ");  PrtChanID(mcchannelid,1);
-		}
-                return -ENODEV;
+	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e))
+		cardpresent = TR_ISAPNP;
+	if (cardpresent == NOTOK) {	/* "channel_id" did not match, report */
+		if (!(ibmtr_debug_trace & TRC_INIT)) return -ENODEV;
+		DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n",
+								PIOaddr);
+		DPRINTK("Expected for ISA: ");
+		PrtChanID(pcchannelid, 1);
+		DPRINTK("           found: ");
+/* BMS Note that this can be misleading, when hardware is flaky, because you
+   are reading it a second time here. So with my flaky hardware, I'll see my-
+   self in this block, with the HW ID matching the ISA ID exactly! */
+		HWPrtChanID(cd_chanid, 2);
+		DPRINTK("Expected for MCA: ");
+		PrtChanID(mcchannelid, 1);
 	}
-
 	/* Now, allocate some of the pl0 buffers for this driver.. */
-
-	/* If called from PCMCIA, ti is already set up, so no need to 
+	/* If called from PCMCIA, it is already set up, so no need to 
 	   waste the memory, just use the existing structure */
-
 #ifndef PCMCIA
-	ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
-	if (ti == NULL) 
-		return -ENOMEM;
-
+	ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL);
+	if (ti == NULL) return -ENOMEM;
 	memset(ti, 0, sizeof(struct tok_info));
-#else
-	ti = dev->priv ; 
+	ti->mmio = t_mmio;
+	dev->priv = ti;		/* this seems like the logical use of the
+				   field ... let's try some empirical tests
+				   using the token-info structure -- that
+				   should fit with out future hope of multiple
+				   adapter support as well /dwm   */
+        for(i=0; i<IBMTR_MAX_ADAPTERS; i++) {
+                if (turbo_io[i] != PIOaddr) continue;
+#if IBMTR_DEBUG_MESSAGES 
+		printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n" ,
+							PIOaddr);
+#endif
+		ti->turbo=1;
+		t_irq=turbo_irq[i];
+        }
 #endif
-	ti->mmio= t_mmio;
 	ti->readlog_pending = 0;
-	init_waitqueue_head(&ti->wait_for_tok_int);
 	init_waitqueue_head(&ti->wait_for_reset);
 
-	dev->priv = ti;     /* this seems like the logical use of the
-                         field ... let's try some empirical tests
-                         using the token-info structure -- that
-                         should fit with out future hope of multiple
-                         adapter support as well /dwm   */
-
-	/* if PCMCIA, then the card is recognized as TR_ISAPNP 
-	 * and there is no need to set up the interrupt, it is already done. */
-        
+	/* if PCMCIA, the card can be recognized as either TR_ISA or TR_ISAPNP
+	 * depending which card is inserted.	*/
+	
 #ifndef PCMCIA
-	switch (cardpresent) 
-	{
-		case TR_ISA:
-			if (intr==0)
-				irq=9; /* irq2 really is irq9 */
-			if (intr==1)
-				irq=3;
-			if (intr==2)
-				irq=6;
-			if (intr==3)
-				irq=7;
-			ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq);
-			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
-			ti->sram=0;
-#if !TR_NEWFORMAT
-			DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);
-#endif
-			break;
-		case TR_MCA:
-			if (intr==0)
-				irq=9;
-			if (intr==1)
-				irq=3;
-			if (intr==2)
-				irq=10;
-			if (intr==3)
-				irq=11;
-			ti->global_int_enable=0;
-			ti->adapter_int_enable=0;
-			ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12);
-			break;
-		case TR_ISAPNP:
-			if (intr==0)
-				irq=9;
-			if (intr==1)
-				irq=3;
-			if (intr==2)
-				irq=10;
-			if (intr==3)
-				irq=11;
-			timeout = jiffies + TR_SPIN_INTERVAL;
-			while(!isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN))
-				if (time_after(jiffies, timeout)) {
-					DPRINTK("Hardware timeout during initialization.\n");
-					kfree(ti);
-					return -ENODEV;
-			        }
-
-			ti->sram=((__u32)isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
-			ti->global_int_enable=PIOaddr+ADAPTINTREL;
-			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
-			break;
-	}
-#endif
+	switch (cardpresent) {
+	case TR_ISA:
+		if (intr == 0) irq = 9;	/* irq2 really is irq9 */
+		if (intr == 1) irq = 3;
+		if (intr == 2) irq = 6;
+		if (intr == 3) irq = 7;
+		ti->adapter_int_enable = PIOaddr + ADAPTINTREL;
+		break;
+	case TR_MCA:
+		if (intr == 0) irq = 9;
+		if (intr == 1) irq = 3;
+		if (intr == 2) irq = 10;
+		if (intr == 3) irq = 11;
+		ti->global_int_enable = 0;
+		ti->adapter_int_enable = 0;
+		ti->sram_virt=(__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12;
+		break;
+	case TR_ISAPNP:
+		if (!t_irq) {
+			if (intr == 0) irq = 9;
+			if (intr == 1) irq = 3;
+			if (intr == 2) irq = 10;
+			if (intr == 3) irq = 11;
+		} else
+			irq=t_irq;
+		timeout = jiffies + TR_SPIN_INTERVAL;
+		while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){
+			if (!time_after(jiffies, timeout)) continue;
+			DPRINTK( "Hardware timeout during initialization.\n");
+			kfree(ti);
+			return -ENODEV;
+		}
+		ti->sram_virt =
+		     ((__u32)readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_EVEN)<<12);
+		ti->adapter_int_enable = PIOaddr + ADAPTINTREL;
+		break;
+	} /*end switch (cardpresent) */
+#endif	/*not PCMCIA */
 
-	if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
-		DPRINTK("irq=%d",irq);
-		if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */
-			DPRINTK(", ti->mmio=%08X",ti->mmio);
-			printk(", segment=%02X",segment);
+	if (ibmtr_debug_trace & TRC_INIT) {	/* just report int */
+		DPRINTK("irq=%d", irq);
+		printk(", sram_virt=0x%x", ti->sram_virt);
+		if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */
+			DPRINTK(", ti->mmio=%08X", ti->mmio);
+			printk(", segment=%02X", segment);
 		}
 		printk(".\n");
 	}
 
 	/* Get hw address of token ring card */
-#if !TR_NEWFORMAT
-	DPRINTK("hw address: ");
-#endif
-	j=0;
-	for (i=0; i<0x18; i=i+2) 
-	{
+	j = 0;
+	for (i = 0; i < 0x18; i = i + 2) {
 		/* technical reference states to do this */
-		temp = isa_readb(ti->mmio + AIP + i) & 0x0f;
-#if !TR_NEWFORMAT
-		printk("%1X",ti->hw_address[j]=temp);
-#else
-		ti->hw_address[j]=temp;
-#endif
-		if(j&1)
-			dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
+		temp = readb(ti->mmio + AIP + i) & 0x0f;
+		ti->hw_address[j] = temp;
+		if (j & 1)
+			dev->dev_addr[(j / 2)] =
+				ti->hw_address[j]+ (ti->hw_address[j - 1] << 4);
 		++j;
 	}
-#ifndef TR_NEWFORMAT
-	printk("\n");
-#endif
-
-	/* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/
-	ti->adapter_type = isa_readb(ti->mmio + AIPADAPTYPE);
+	/* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,... */
+	ti->adapter_type = readb(ti->mmio + AIPADAPTYPE);
 
 	/* get Data Rate:  F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */
-	ti->data_rate = isa_readb(ti->mmio + AIPDATARATE);
+	ti->data_rate = readb(ti->mmio + AIPDATARATE);
 
 	/* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */
-	ti->token_release = isa_readb(ti->mmio + AIPEARLYTOKEN);
+	ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
 
 	/* How much shared RAM is on adapter ? */
-#ifdef PCMCIA
-	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
-	ibmtr_mem_base = ti->sram_base << 12 ; 
-#else
-	ti->avail_shared_ram = get_sram_size(ti);
-#endif
-	/* We need to set or do a bunch of work here based on previous results.. */
+	if (ti->turbo) {
+		ti->avail_shared_ram=127;
+	} else {
+		ti->avail_shared_ram = get_sram_size(ti);/*in 512 byte units */
+	}
+	/* We need to set or do a bunch of work here based on previous results*/
 	/* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
-	ti->shared_ram_paging = isa_readb(ti->mmio + AIPSHRAMPAGE);
+	ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
 
-        /* Available DHB  4Mb size:   F=2048, E=4096, D=4464 */
-	switch (isa_readb(ti->mmio + AIP4MBDHB)) {
-	case 0xe : 
-		ti->dhb_size4mb = 4096;
-		break; 
-	case 0xd : 
-		ti->dhb_size4mb = 4464;
-		break; 
-	default  : 
-		ti->dhb_size4mb = 2048;
-		break; 
+	/* Available DHB  4Mb size:   F=2048, E=4096, D=4464 */
+	switch (readb(ti->mmio + AIP4MBDHB)) {
+	case 0xe: ti->dhb_size4mb = 4096; break;
+	case 0xd: ti->dhb_size4mb = 4464; break;
+	default:  ti->dhb_size4mb = 2048; break;
 	}
 
 	/* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
-	switch (isa_readb(ti->mmio + AIP16MBDHB)) {
-	case 0xe : 
-		ti->dhb_size16mb = 4096;
-		break; 
-	case 0xd : 
-		ti->dhb_size16mb = 8192;
-		break; 
-	case 0xc : 
-		ti->dhb_size16mb = 16384;
-		break; 
-	case 0xb : 
-		ti->dhb_size16mb = 17960;
-		break; 
-	default  : 
-		ti->dhb_size16mb = 2048;
-		break; 
+	switch (readb(ti->mmio + AIP16MBDHB)) {
+	case 0xe: ti->dhb_size16mb = 4096; break;
+	case 0xd: ti->dhb_size16mb = 8192; break;
+	case 0xc: ti->dhb_size16mb = 16384; break;
+	case 0xb: ti->dhb_size16mb = 17960; break;
+	default:  ti->dhb_size16mb = 2048; break;
 	}
 
-#if !TR_NEWFORMAT
-	DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, "
-		"dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type,
-		ti->data_rate, ti->token_release, ti->avail_shared_ram/2,
-		ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb);
-#endif
-
-	/*	We must figure out how much shared memory space this adapter
-	 *	will occupy so that if there are two adapters we can fit both
-	 *	in.  Given a choice, we will limit this adapter to 32K.  The
-	 *	maximum space will will use for two adapters is 64K so if the
-	 *	adapter we are working on demands 64K (it also doesn't support
-	 *	paging), then only one adapter can be supported.  
+	/*    We must figure out how much shared memory space this adapter
+	 *    will occupy so that if there are two adapters we can fit both
+	 *    in.  Given a choice, we will limit this adapter to 32K.  The
+	 *    maximum space will will use for two adapters is 64K so if the
+	 *    adapter we are working on demands 64K (it also doesn't support
+	 *    paging), then only one adapter can be supported.  
 	 */
 
 	/*
-	 *	determine how much of total RAM is mapped into PC space 
+	 *    determine how much of total RAM is mapped into PC space 
 	 */
-	ti->mapped_ram_size=1<<((((isa_readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4);
-	ti->page_mask=0;
-	if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */
-		ti->mapped_ram_size = ti->avail_shared_ram;
-	} else {
-#ifdef ENABLE_PAGING
-		unsigned char pg_size=0;
-#endif
-
-#if !TR_NEWFORMAT
-		DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
-#endif
+	ti->mapped_ram_size= /*sixteen to onehundredtwentyeight 512byte blocks*/
+	    1<< ((readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03) + 4);
+	ti->page_mask = 0;
+	if (ti->turbo)  ti->page_mask=0xf0;
+	else if (ti->shared_ram_paging == 0xf);  /* No paging in adapter */
+	else {
 #ifdef ENABLE_PAGING
-	switch(ti->shared_ram_paging) 
-	{
+		unsigned char pg_size = 0;
+		/* BMS:   page size: PCMCIA, use configuration register;
+		   ISAPNP, use LANAIDC config tool from www.ibm.com  */
+		switch (ti->shared_ram_paging) {
 		case 0xf:
 			break;
 		case 0xe:
-			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-			pg_size=32;   /* 16KB page size */
+			ti->page_mask = (ti->mapped_ram_size == 32) ? 0xc0 : 0;
+			pg_size = 32;	/* 16KB page size */
 			break;
 		case 0xd:
-			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-			pg_size=64;   /* 32KB page size */
+			ti->page_mask = (ti->mapped_ram_size == 64) ? 0x80 : 0;
+			pg_size = 64;	/* 32KB page size */
 			break;
 		case 0xc:
-		        switch (ti->mapped_ram_size) {
-			  case 32:
-			    ti->page_mask=0xc0;
-                            pg_size=32;
-                            break;
-			  case 64:
-                            ti->page_mask=0x80;
-                            pg_size=64;
-                            break;
-                        }
+			switch (ti->mapped_ram_size) {
+			case 32:
+				ti->page_mask = 0xc0;
+				pg_size = 32;
+				break;
+			case 64:
+				ti->page_mask = 0x80;
+				pg_size = 64;
+				break;
+			}
 			break;
 		default:
-			DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
+			DPRINTK("Unknown shared ram paging info %01X\n",
+							ti->shared_ram_paging);
 			kfree(ti);
 			return -ENODEV;
 			break;
-	}
+		} /*end switch shared_ram_paging */
 
- 	if (ibmtr_debug_trace & TRC_INIT)
- 	  DPRINTK("Shared RAM paging code: "
- 		 "%02X mapped RAM size: %dK shared RAM size: %dK page mask: %0xX\n:",
- 		 ti->shared_ram_paging, ti->mapped_ram_size/2, ti->avail_shared_ram/2, ti->page_mask);
-
-	if (ti->page_mask) {
-		if (pg_size > ti->mapped_ram_size) {
-			DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
-				pg_size/2, ti->mapped_ram_size/2);
-				ti->page_mask = 0;    /* reset paging */
-                }
-	} else if (pg_size > ti->mapped_ram_size) {
-	                DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
-				pg_size/2, ti->mapped_ram_size/2);
-	}
-#endif
+		if (ibmtr_debug_trace & TRC_INIT)
+			DPRINTK("Shared RAM paging code: %02X, "
+				"mapped RAM size: %dK, shared RAM size: %dK, "
+				"page mask: %02X\n:",
+				ti->shared_ram_paging, ti->mapped_ram_size / 2,
+				ti->avail_shared_ram / 2, ti->page_mask);
+#endif	/*ENABLE_PAGING */
 	}
+
+#ifndef PCMCIA
 	/* finish figuring the shared RAM address */
-	if (cardpresent==TR_ISA) {
-		static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000};
+	if (cardpresent == TR_ISA) {
+		static __u32 ram_bndry_mask[] =
+			{ 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000 };
 		__u32 new_base, rrr_32, chk_base, rbm;
 
-		rrr_32 = ((isa_readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2) & 0x00000003;
+		rrr_32=readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03;
 		rbm = ram_bndry_mask[rrr_32];
-		new_base = (ibmtr_mem_base + (~rbm)) & rbm; /* up to boundary */
-		chk_base = new_base + (ti->mapped_ram_size<<9);
+		new_base = (ibmtr_mem_base + (~rbm)) & rbm;/* up to boundary */
+		chk_base = new_base + (ti->mapped_ram_size << 9);
 		if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) {
-			DPRINTK("Shared RAM for this adapter (%05x) exceeds driver"
-				" limit (%05x), adapter not started.\n",
-				chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
+			DPRINTK("Shared RAM for this adapter (%05x) exceeds "
+			"driver limit (%05x), adapter not started.\n",
+			chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
 			kfree(ti);
-                        return -ENODEV;
-		} else {  /* seems cool, record what we have figured out */
+			return -ENODEV;
+		} else { /* seems cool, record what we have figured out */
 			ti->sram_base = new_base >> 12;
 			ibmtr_mem_base = chk_base;
 		}
 	}
-
-#if !TR_NEWFORMAT
-	DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2);
-#endif
+	else  ti->sram_base = ti->sram_virt >> 12;
 
 	/* The PCMCIA has already got the interrupt line and the io port, 
 	   so no chance of anybody else getting it - MLP */
-
-#ifndef PCMCIA
-	if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) {
-		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",irq);
+	if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) {
+		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",
+					irq);
 		kfree(ti);
 		return -ENODEV;
 	}
- 
 	/*?? Now, allocate some of the PIO PORTs for this driver.. */
-	request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range as busy */
+	/* record PIOaddr range as busy */
+	request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr");
+	if (!version_printed++) {
+		printk(version);
+	}
 #endif
-
-#if !TR_NEWFORMAT
-	DPRINTK("%s",version); /* As we have passed card identification,
-                                  let the world know we're here! */
-#else
-
-	if (version) {
-	        printk("%s",version);
-                version = NULL;
-        }
 	DPRINTK("%s %s found\n",
-		channel_def[cardpresent-1], adapter_def(ti->adapter_type));
+		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
 	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
-	        irq, PIOaddr, ti->mapped_ram_size/2);
+			irq, PIOaddr, ti->mapped_ram_size / 2);
 	DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
 		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- 	if (ti->page_mask)
- 	  DPRINTK("Shared RAM paging enabled. Page size: %uK Shared Ram size %dK\n",
- 		  ((ti->page_mask ^ 0xff)+1)>>2,ti->avail_shared_ram/2);
- 	else
- 	  DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n",ti->page_mask);
-#endif
+	if (ti->page_mask)
+		DPRINTK("Shared RAM paging enabled. "
+			"Page size: %uK Shared Ram size %dK\n",
+			((ti->page_mask^0xff)+1) >>2, ti->avail_shared_ram / 2);
+	else
+		DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n",
+								ti->page_mask);
+
 	/* Calculate the maximum DHB we can use */
+	/* two cases where avail_shared_ram doesn't equal mapped_ram_size:
+	    1. avail_shared_ram is 127 but mapped_ram_size is 128 (typical)
+	    2. user has configured adapter for less than avail_shared_ram
+	       but is not using paging (she should use paging, I believe)
+	*/
 	if (!ti->page_mask) {
-	  ti->avail_shared_ram=ti->mapped_ram_size;
+		ti->avail_shared_ram=
+				MIN(ti->mapped_ram_size,ti->avail_shared_ram);
 	}
+
 	switch (ti->avail_shared_ram) {
-	case  16 : /* 8KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
+	case 16:		/* 8KB shared RAM */
+		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048);
 		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 2;
+		ti->rbuf_cnt4=2;
 		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
 		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 2;
+		ti->rbuf_cnt16=2;
 		break;
-	case  32 : /* 16KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
-		ti->rbuf_len4 = 520;
-		ti->rbuf_cnt4 = 9;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
-		ti->rbuf_len16 = 1032; /* 1024 usable */
-		ti->rbuf_cnt16 = 4;
+	case 32:		/* 16KB shared RAM */
+		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
+		ti->rbuf_len4 = 1032;
+		ti->rbuf_cnt4=4;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096);
+		ti->rbuf_len16 = 1032;	/*1024 usable */
+		ti->rbuf_cnt16=4;
 		break;
-	case  64 : /* 32KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
+	case 64:		/* 32KB shared RAM */
+		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
 		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 6;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
+		ti->rbuf_cnt4=6;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240);
 		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 10;
+		ti->rbuf_cnt16=6;
 		break;
-	case 127 : /* 63KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
+	case 127:		/* 63.5KB shared RAM */
+		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
 		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 6;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
+		ti->rbuf_cnt4=6;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384);
 		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 16;
+		ti->rbuf_cnt16=16;
 		break;
-	case 128 : /* 64KB shared RAM */
-		ti->dhb_size4mb  = MIN(ti->dhb_size4mb, 2048);
+	case 128:		/* 64KB   shared RAM */
+		ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464);
 		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 6;
-		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048);
+		ti->rbuf_cnt4=6;
+		ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960);
 		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 18;
+		ti->rbuf_cnt16=16;
 		break;
-	default  :
-		ti->dhb_size4mb  = 2048;
+	default:
+		ti->dhb_size4mb = 2048;
 		ti->rbuf_len4 = 1032;
-		ti->rbuf_cnt4 = 2;
+		ti->rbuf_cnt4=2;
 		ti->dhb_size16mb = 2048;
 		ti->rbuf_len16 = 1032;
-		ti->rbuf_cnt16 = 2;
+		ti->rbuf_cnt16=2;
 		break;
 	}
-
-	ti->maxmtu16 = (ti->rbuf_len16*ti->rbuf_cnt16)-((ti->rbuf_cnt16)<<3)-TR_HLEN;
-	ti->maxmtu4  = (ti->rbuf_len4*ti->rbuf_cnt4)-((ti->rbuf_cnt4)<<3)-TR_HLEN;
-	DPRINTK("Maximum MTU 16Mbps: %d, 4Mbps: %d\n",
-		ti->maxmtu16, ti->maxmtu4);
-
-	dev->base_addr=PIOaddr; /* set the value for device */
-
+	/* this formula is not smart enough for the paging case
+	ti->rbuf_cnt<x> = (ti->avail_shared_ram * BLOCKSZ - ADAPT_PRIVATE -
+			ARBLENGTH - SSBLENGTH - DLC_MAX_SAP * SAPLENGTH -
+			DLC_MAX_STA * STALENGTH - ti->dhb_size<x>mb * NUM_DHB -
+			SRBLENGTH - ASBLENGTH) / ti->rbuf_len<x>;
+	*/
+	ti->maxmtu16 = (ti->rbuf_len16 - 8) * ti->rbuf_cnt16  - TR_HLEN;
+	ti->maxmtu4 = (ti->rbuf_len4 - 8) * ti->rbuf_cnt4 - TR_HLEN;
+	/*BMS assuming 18 bytes of Routing Information (usually works) */
+	DPRINTK("Maximum Receive Internet Protocol MTU 16Mbps: %d, 4Mbps: %d\n",
+						     ti->maxmtu16, ti->maxmtu4);
+
+	dev->base_addr = PIOaddr;	/* set the value for device */
+	dev->mem_start = ti->sram_base << 12;
+	dev->mem_end = dev->mem_start + (ti->mapped_ram_size << 9) - 1;
 	trdev_init(dev);
-	tok_init_card(dev);
+	return 0;   /* Return 0 to indicate we have found a Token Ring card. */
+}				/*ibmtr_probe1() */
 
-	return 0;  /* Return 0 to indicate we have found a Token Ring card. */
-}
+/*****************************************************************************/
 
 /* query the adapter for the size of shared RAM  */
+/* the function returns the RAM size in units of 512 bytes */
 
-static unsigned char __init get_sram_size(struct tok_info *adapt_info)
+static unsigned char __devinit get_sram_size(struct tok_info *adapt_info)
 {
-
 	unsigned char avail_sram_code;
-	static unsigned char size_code[]={ 0,16,32,64,127,128 };
+	static unsigned char size_code[] = { 0, 16, 32, 64, 127, 128 };
 	/* Adapter gives
 	   'F' -- use RRR bits 3,2
 	   'E' -- 8kb   'D' -- 16kb
@@ -776,30 +773,27 @@
 	   'B' - 64KB less 512 bytes at top
 	   (WARNING ... must zero top bytes in INIT */
 
-	avail_sram_code=0xf-isa_readb(adapt_info->mmio + AIPAVAILSHRAM);
-	if (avail_sram_code)
-		return size_code[avail_sram_code];
-	else  /* for code 'F', must compute size from RRR(3,2) bits */
-		return 1<<((isa_readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4);
+	avail_sram_code = 0xf - readb(adapt_info->mmio + AIPAVAILSHRAM);
+	if (avail_sram_code) return size_code[avail_sram_code];
+	else		/* for code 'F', must compute size from RRR(3,2) bits */
+		return 1 <<
+		 ((readb(adapt_info->mmio+ACA_OFFSET+ACA_RW+RRR_ODD)>>2&3)+4);
 }
 
-static int __init trdev_init(struct net_device *dev)
-{
-	struct tok_info *ti=(struct tok_info *)dev->priv;
+/*****************************************************************************/
 
-	/* init the spinlock */
-	spin_lock_init(&ti->lock);
+static int __devinit trdev_init(struct net_device *dev)
+{
+	struct tok_info *ti = (struct tok_info *) dev->priv;
 
 	SET_PAGE(ti->srb_page);
-	ti->open_status		= CLOSED;
-
-	dev->init		= tok_init_card;
-	dev->open		= tok_open;
-	dev->stop		= tok_close;
-	dev->hard_start_xmit	= tok_send_packet;
-	dev->get_stats 		= tok_get_stats;
+        ti->open_failure = NO    ;
+	dev->open = tok_open;
+	dev->stop = tok_close;
+	dev->hard_start_xmit = tok_send_packet;
+	dev->get_stats = tok_get_stats;
 	dev->set_multicast_list = tok_set_multicast_list;
-	dev->change_mtu         = ibmtr_change_mtu;
+	dev->change_mtu = ibmtr_change_mtu;
 
 #ifndef MODULE
 #ifndef PCMCIA
@@ -809,23 +803,173 @@
 	return 0;
 }
 
+/*****************************************************************************/
+
+static int tok_init_card(struct net_device *dev)
+{
+	struct tok_info *ti;
+	short PIOaddr;
+	unsigned long i;
+
+	PIOaddr = dev->base_addr;
+	ti = (struct tok_info *) dev->priv;
+	/* Special processing for first interrupt after reset */
+	ti->do_tok_int = FIRST_INT;
+	/* Reset adapter */
+	writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
+	outb(0, PIOaddr + ADAPTRESET);
+
+	current->state=TASK_UNINTERRUPTIBLE;
+	schedule_timeout(TR_RST_TIME); /* wait 50ms */
+
+	outb(0, PIOaddr + ADAPTRESETREL);
+#ifdef ENABLE_PAGING
+	if (ti->page_mask)
+		writeb(SRPR_ENABLE_PAGING,ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN);
+#endif
+	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	i = sleep_on_timeout(&ti->wait_for_reset, 4 * HZ);
+	return i? 0 : -EAGAIN;
+}
+
+/*****************************************************************************/
+static int tok_open(struct net_device *dev)
+{
+	struct tok_info *ti = (struct tok_info *) dev->priv;
+	int i;
+
+	/*the case we were left in a failure state during a previous open */
+	if (ti->open_failure == YES) {
+		DPRINTK("Last time you were disconnected, how about now?\n");
+		printk("You can't insert with an ICS connector half-cocked.\n");
+	}
+
+	ti->open_status  = CLOSED; /* CLOSED or OPEN      */
+	ti->sap_status   = CLOSED; /* CLOSED or OPEN      */
+	ti->open_failure =     NO; /* NO     or YES       */
+	ti->open_mode    = MANUAL; /* MANUAL or AUTOMATIC */
+	/* 12/2000 not typical Linux, but we can use RUNNING to let us know when
+	the network has crapped out or cables are disconnected. Useful because
+	the IFF_UP flag stays up the whole time, until ifconfig tr0 down.
+	*/
+	dev->flags &= ~IFF_RUNNING;
+
+	ti->sram_virt &= ~1; /* to reverse what we do in tok_close */
+	/* init the spinlock */
+	ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
+	i = tok_init_card(dev);
+	if (i) return i;
+
+	while (1){
+		tok_open_adapter((unsigned long) dev);
+		i= interruptible_sleep_on_timeout(&ti->wait_for_reset, 25 * HZ);
+		/* sig catch: estimate opening adapter takes more than .5 sec*/
+		if (i>(245*HZ)/10) break; /* fancier than if (i==25*HZ) */
+		if (i==0) break;
+		if (ti->open_status == OPEN && ti->sap_status==OPEN) {
+			netif_start_queue(dev);
+			MOD_INC_USE_COUNT;
+			DPRINTK("Adapter is up and running\n");
+			return 0;
+		}
+		current->state=TASK_INTERRUPTIBLE;
+		i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */
+		if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */
+	}
+	outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/
+	DPRINTK("TERMINATED via signal\n");	/*BMS useful */
+	return -EAGAIN;
+}
+
+/*****************************************************************************/
+
+#define COMMAND_OFST             0
+#define OPEN_OPTIONS_OFST        8
+#define NUM_RCV_BUF_OFST        24
+#define RCV_BUF_LEN_OFST        26
+#define DHB_LENGTH_OFST         28
+#define NUM_DHB_OFST            30
+#define DLC_MAX_SAP_OFST        32
+#define DLC_MAX_STA_OFST        33
+
+void tok_open_adapter(unsigned long dev_addr)
+{
+	struct net_device *dev = (struct net_device *) dev_addr;
+	struct tok_info *ti;
+	int i;
+
+	ti = (struct tok_info *) dev->priv;
+	SET_PAGE(ti->init_srb_page); 
+	writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+	for (i = 0; i < sizeof(struct dir_open_adapter); i++)
+		writeb(0, ti->init_srb + i);
+	writeb(DIR_OPEN_ADAPTER, ti->init_srb + COMMAND_OFST);
+	writew(htons(OPEN_PASS_BCON_MAC), ti->init_srb + OPEN_OPTIONS_OFST);
+	if (ti->ring_speed == 16) {
+		writew(htons(ti->dhb_size16mb), ti->init_srb + DHB_LENGTH_OFST);
+		writew(htons(ti->rbuf_cnt16), ti->init_srb + NUM_RCV_BUF_OFST);
+		writew(htons(ti->rbuf_len16), ti->init_srb + RCV_BUF_LEN_OFST);
+	} else {
+		writew(htons(ti->dhb_size4mb), ti->init_srb + DHB_LENGTH_OFST);
+		writew(htons(ti->rbuf_cnt4), ti->init_srb + NUM_RCV_BUF_OFST);
+		writew(htons(ti->rbuf_len4), ti->init_srb + RCV_BUF_LEN_OFST);
+	}
+	writeb(NUM_DHB,		/* always 2 */ ti->init_srb + NUM_DHB_OFST);
+	writeb(DLC_MAX_SAP, ti->init_srb + DLC_MAX_SAP_OFST);
+	writeb(DLC_MAX_STA, ti->init_srb + DLC_MAX_STA_OFST);
+	ti->srb = ti->init_srb;	/* We use this one in the interrupt handler */
+	ti->srb_page = ti->init_srb_page;
+	DPRINTK("Opening adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n",
+		readb(ti->init_srb + NUM_DHB_OFST),
+		ntohs(readw(ti->init_srb + DHB_LENGTH_OFST)),
+		ntohs(readw(ti->init_srb + NUM_RCV_BUF_OFST)),
+		ntohs(readw(ti->init_srb + RCV_BUF_LEN_OFST)));
+	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+}
+
+/*****************************************************************************/
+
+static void open_sap(unsigned char type, struct net_device *dev)
+{
+	int i;
+	struct tok_info *ti = (struct tok_info *) dev->priv;
+
+	SET_PAGE(ti->srb_page);
+	for (i = 0; i < sizeof(struct dlc_open_sap); i++)
+		writeb(0, ti->srb + i);
+
+#define MAX_I_FIELD_OFST        14
+#define SAP_VALUE_OFST          16
+#define SAP_OPTIONS_OFST        17
+#define STATION_COUNT_OFST      18
+
+	writeb(DLC_OPEN_SAP, ti->srb + COMMAND_OFST);
+	writew(htons(MAX_I_FIELD), ti->srb + MAX_I_FIELD_OFST);
+	writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, ti->srb+ SAP_OPTIONS_OFST);
+	writeb(SAP_OPEN_STATION_CNT, ti->srb + STATION_COUNT_OFST);
+	writeb(type, ti->srb + SAP_VALUE_OFST);
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+}
+
+
+/*****************************************************************************/
 
 static void tok_set_multicast_list(struct net_device *dev)
 {
-	struct tok_info *ti=(struct tok_info *)dev->priv;
+	struct tok_info *ti = (struct tok_info *) dev->priv;
 	struct dev_mc_list *mclist;
 	unsigned char address[4];
 
 	int i;
 
-	if(ti->open_status==CLOSED)
-		return;
-
+	/*BMS the next line is CRUCIAL or you may be sad when you */
+	/*BMS ifconfig tr down or hot unplug a PCMCIA card ??hownowbrowncow*/
+	if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return;
 	address[0] = address[1] = address[2] = address[3] = 0;
-
 	mclist = dev->mc_list;
-	for (i=0; i< dev->mc_count; i++)
-	{
+	for (i = 0; i < dev->mc_count; i++) {
 		address[0] |= mclist->dmi_addr[2];
 		address[1] |= mclist->dmi_addr[3];
 		address[2] |= mclist->dmi_addr[4];
@@ -833,76 +977,168 @@
 		mclist = mclist->next;
 	}
 	SET_PAGE(ti->srb_page);
-	for (i=0; i<sizeof(struct srb_set_funct_addr); i++)
-		isa_writeb(0, ti->srb+i);
+	for (i = 0; i < sizeof(struct srb_set_funct_addr); i++)
+		writeb(0, ti->srb + i);
 
-	isa_writeb(DIR_SET_FUNC_ADDR, 
-               ti->srb + offsetof(struct srb_set_funct_addr, command));
+#define FUNCT_ADDRESS_OFST 6
 
+	writeb(DIR_SET_FUNC_ADDR, ti->srb + COMMAND_OFST);
+	for (i = 0; i < 4; i++) 
+		writeb(address[i], ti->srb + FUNCT_ADDRESS_OFST + i);
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+#if TR_VERBOSE
 	DPRINTK("Setting functional address: ");
-
-	for (i=0; i<4; i++)
-	{
-		isa_writeb(address[i], 
-		ti->srb + offsetof(struct srb_set_funct_addr, funct_address)+i);
-		printk("%02X ", address[i]);
-	}
-	isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	for (i=0;i<4;i++)  printk("%02X ", address[i]);
 	printk("\n");
+#endif
 }
 
-static int tok_open(struct net_device *dev)
-{
-	struct tok_info *ti=(struct tok_info *)dev->priv;
+/*****************************************************************************/
 
-	if (ti->open_status==CLOSED) tok_init_card(dev);
+#define STATION_ID_OFST 4
 
-	if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset);
+static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct tok_info *ti;
+	unsigned long flags;
+	ti = (struct tok_info *) dev->priv;
 
-	if (ti->open_status==SUCCESS) {
-		/* NEED to see smem size *AND* reset high 512 bytes if needed */
-		netif_start_queue(dev);
-		MOD_INC_USE_COUNT;
+        netif_stop_queue(dev);
 
-		return 0;
-	} else return -EAGAIN;
+	/* lock against other CPUs */
+	spin_lock_irqsave(&(ti->lock), flags);
 
-}
+	/* Save skb; we'll need it when the adapter asks for the data */
+	ti->current_skb = skb;
+	SET_PAGE(ti->srb_page);
+	writeb(XMIT_UI_FRAME, ti->srb + COMMAND_OFST);
+	writew(ti->exsap_station_id, ti->srb + STATION_ID_OFST);
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	spin_unlock_irqrestore(&(ti->lock), flags);
+	dev->trans_start = jiffies;
+	return 0;
+}
+
+/*****************************************************************************/
 
 static int tok_close(struct net_device *dev)
 {
+	struct tok_info *ti = (struct tok_info *) dev->priv;
 
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-
-	if(ti->open_status!=CLOSED) {
-		netif_stop_queue(dev);
-		SET_PAGE(ti->srb_page);	
-		isa_writeb(DIR_CLOSE_ADAPTER,
-	       	ti->srb + offsetof(struct srb_close_adapter, command));
-		isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-		ti->open_status=CLOSED;
+	/* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */
+	/* unloading the module from memory, and then if a timer pops, ouch */
+	del_timer(&ti->tr_timer);
+	outb(0, dev->base_addr + ADAPTRESET);
+	ti->sram_virt |= 1;
+	ti->open_status = CLOSED;
 
-		sleep_on(&ti->wait_for_tok_int);
+	netif_stop_queue(dev);
+	DPRINTK("Adapter is closed.\n");
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
-		SET_PAGE(ti->srb_page);
-		if (isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
-			DPRINTK("close adapter failed: %02X\n",
-				(int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
+/*****************************************************************************/
 
-#ifdef PCMCIA
-		ti->sram = 0 ;
-#endif
-		DPRINTK("Adapter closed.\n");
-		MOD_DEC_USE_COUNT;
+#define RETCODE_OFST		2
+#define OPEN_ERROR_CODE_OFST	6
+#define ASB_ADDRESS_OFST        8
+#define SRB_ADDRESS_OFST        10
+#define ARB_ADDRESS_OFST        12
+#define SSB_ADDRESS_OFST        14
+
+static char *printphase[]= {"Lobe media test","Physical insertion",
+	      "Address verification","Roll call poll","Request Parameters"};
+static char *printerror[]={"Function failure","Signal loss","Reserved",
+		"Frequency error","Timeout","Ring failure","Ring beaconing",
+		"Duplicate node address",
+		"Parameter request-retry count exceeded","Remove received",
+		"IMPL force received","Duplicate modifier",
+		"No monitor detected","Monitor contention failed for RPL"};
+
+void dir_open_adapter (struct net_device *dev) {
+
+        struct tok_info *ti = (struct tok_info *) dev->priv;
+        unsigned char ret_code;
+        __u16 err;
+
+        ti->srb = ntohs(readw(ti->init_srb + SRB_ADDRESS_OFST));
+        ti->ssb = ntohs(readw(ti->init_srb + SSB_ADDRESS_OFST));
+        ti->arb = ntohs(readw(ti->init_srb + ARB_ADDRESS_OFST));
+        ti->asb = ntohs(readw(ti->init_srb + ASB_ADDRESS_OFST));
+        if (ti->page_mask) {
+                ti->srb_page = (ti->srb >> 8) & ti->page_mask;
+                ti->srb &= ~(ti->page_mask << 8);
+                ti->ssb_page = (ti->ssb >> 8) & ti->page_mask;
+                ti->ssb &= ~(ti->page_mask << 8);
+                ti->arb_page = (ti->arb >> 8) & ti->page_mask;
+                ti->arb &= ~(ti->page_mask << 8);
+                ti->asb_page = (ti->asb >> 8) & ti->page_mask;
+                ti->asb &= ~(ti->page_mask << 8);
+        }
+        ti->srb += ti->sram_virt;
+        ti->ssb += ti->sram_virt;
+        ti->arb += ti->sram_virt;
+        ti->asb += ti->sram_virt;
+        ti->current_skb = NULL;
+        ret_code = readb(ti->init_srb + RETCODE_OFST);
+        err = ntohs(readw(ti->init_srb + OPEN_ERROR_CODE_OFST));
+        if (!ret_code) {
+		ti->open_status = OPEN; /* TR adapter is now available */
+                if (ti->open_mode == AUTOMATIC) {
+			DPRINTK("Adapter reopened.\n");
+                }
+                writeb(~SRB_RESP_INT, ti->mmio+ACA_OFFSET+ACA_RESET+ISRP_ODD);
+                open_sap(EXTENDED_SAP, dev);
+		return;
 	}
-
-	return 0;
+	ti->open_failure = YES;
+	if (ret_code == 7){
+               if (err == 0x24) {
+			if (!ti->auto_speedsave) {
+				DPRINTK("Open failed: Adapter speed must match "
+                                 "ring speed if Automatic Ring Speed Save is "
+				 "disabled.\n");
+				ti->open_action = FAIL;
+			}else
+				DPRINTK("Retrying open to adjust to "
+					"ring speed, ");
+                } else if (err == 0x2d) {
+			DPRINTK("Physical Insertion: No Monitor Detected, ");
+			printk("retrying after %ds delay...\n",
+					TR_RETRY_INTERVAL/HZ);
+                } else if (err == 0x11) {
+			DPRINTK("Lobe Media Function Failure (0x11), ");
+			printk(" retrying after %ds delay...\n",
+					TR_RETRY_INTERVAL/HZ);
+                } else {
+			char **prphase = printphase;
+			char **prerror = printerror;
+			DPRINTK("TR Adapter misc open failure, error code = ");
+			printk("0x%x, Phase: %s, Error: %s\n",
+				err, prphase[err/16 -1], prerror[err%16 -1]);
+			printk(" retrying after %ds delay...\n",
+					TR_RETRY_INTERVAL/HZ);
+                }
+        } else DPRINTK("open failed: ret_code = %02X..., ", ret_code);
+	if (ti->open_action != FAIL) {
+		if (ti->open_mode==AUTOMATIC){
+			ti->open_action = REOPEN;
+			ibmtr_reset_timer(&(ti->tr_timer), dev);
+			return;
+		}
+		wake_up(&ti->wait_for_reset);
+		return;
+	}
+	DPRINTK("FAILURE, CAPUT\n");
 }
 
-void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+/******************************************************************************/
+
+void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned char status;
+	/*  unsigned char status_even ; */
 	struct tok_info *ti;
 	struct net_device *dev;
 #ifdef ENABLE_PAGING
@@ -911,839 +1147,621 @@
 
 	dev = dev_id;
 #if TR_VERBOSE
-	DPRINTK("Int from tok_driver, dev : %p\n",dev);
+	DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs);
 #endif
-	ti  = (struct tok_info *) dev->priv;
+	ti = (struct tok_info *) dev->priv;
+	if (ti->sram_virt & 1)
+		return;         /* PCMCIA card extraction flag */
 	spin_lock(&(ti->lock));
 #ifdef ENABLE_PAGING
-	save_srpr=isa_readb(ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN);
+	save_srpr = readb(ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
 #endif
 
-      	/* Disable interrupts till processing is finished */
-	isa_writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
+	/* Disable interrupts till processing is finished */
+	writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
 
 	/* Reset interrupt for ISA boards */
-        if (ti->adapter_int_enable)
-                outb(0,ti->adapter_int_enable);
-	else
-		outb(0,ti->global_int_enable);
-
-
-	switch (ti->do_tok_int) {
-
-	      case NOT_FIRST:
-
-		/*  Begin the regular interrupt handler HERE inline to avoid
-		    the extra levels of logic and call depth for the
-		    original solution.   */
-
-		status=isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
-#ifdef PCMCIA
-      		/* Check if the PCMCIA card was pulled. */
-    		if (status == 0xFF)
-       		{
-		          DPRINTK("PCMCIA card removed.\n");
-                          ti->open_status=CLOSED;
-			  goto return_point ; 
-       		}
-
-    	        /* Check ISRP EVEN too. */
-      	        if ( isa_readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
-    	        {
-         		 DPRINTK("PCMCIA card removed.\n");
-                         ti->open_status=CLOSED;
-			 goto return_point ; 
-      		}
+	if (ti->adapter_int_enable)
+		outb(0, ti->adapter_int_enable);
+	else /* used for PCMCIA cards */
+		outb(0, ti->global_int_enable);
+        if (ti->do_tok_int == FIRST_INT){
+                initial_tok_int(dev);
+#ifdef ENABLE_PAGING
+                writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
 #endif
+                spin_unlock(&(ti->lock));
+                return;
+        }
+	/*  Begin interrupt handler HERE inline to avoid the extra
+	    levels of logic and call depth for the original solution. */
+	status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
+	/*BMSstatus_even = readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) */
+	/*BMSdebugprintk("tok_interrupt: ISRP_ODD = 0x%x ISRP_EVEN = 0x%x\n", */
+	/*BMS                                       status,status_even);      */
 
+	if (status & ADAP_CHK_INT) {
+		int i;
+		__u32 check_reason;
+		__u8 check_reason_page = 0;
+		check_reason =
+			ntohs(readw(ti->mmio+ ACA_OFFSET+ACA_RW + WWCR_EVEN));
+		if (ti->page_mask) {
+			check_reason_page = (check_reason >> 8) & ti->page_mask;
+			check_reason &= ~(ti->page_mask << 8);
+		}
+		check_reason += ti->sram_virt;
+		SET_PAGE(check_reason_page);
 
-		if (status & ADAP_CHK_INT) {
-
-			int i;
-			__u32 check_reason;
-                        __u8  check_reason_page=0;
-
-			check_reason=ntohs(isa_readw(ti->sram + ACA_OFFSET + ACA_RW +WWCR_EVEN));
-			if (ti->page_mask) {
-			  check_reason_page=(check_reason>>8) & ti->page_mask;
-			  check_reason &= ~(ti->page_mask << 8);
+		DPRINTK("Adapter check interrupt\n");
+		DPRINTK("8 reason bytes follow: ");
+		for (i = 0; i < 8; i++, check_reason++)
+			printk("%02X ", (int) readb(check_reason));
+		printk("\n");
+		writeb(~ADAP_CHK_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
+		status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRA_EVEN);
+		DPRINTK("ISRA_EVEN == 0x02%x\n",status);
+		ti->open_status = CLOSED;
+		ti->sap_status  = CLOSED;
+		ti->open_mode   = AUTOMATIC;
+		dev->flags &= ~IFF_RUNNING;
+		netif_stop_queue(dev);
+		ti->open_action = RESTART;
+		outb(0, dev->base_addr + ADAPTRESET);
+		ibmtr_reset_timer(&(ti->tr_timer), dev);/*BMS try to reopen*/
+		return;
+	}
+	if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
+		& (TCR_INT | ERR_INT | ACCESS_INT)) {
+		DPRINTK("adapter error: ISRP_EVEN : %02x\n",
+			(int)readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRP_EVEN));
+		writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
+			ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
+		status= readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRA_EVEN);/*BMS*/
+		DPRINTK("ISRA_EVEN == 0x02%x\n",status);/*BMS*/
+                writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+#ifdef ENABLE_PAGING
+                writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
+#endif
+                spin_unlock(&(ti->lock));
+                return;
+        }
+	if (status & SRB_RESP_INT) {	/* SRB response */
+		SET_PAGE(ti->srb_page);
+#if TR_VERBOSE
+		DPRINTK("SRB resp: cmd=%02X rsp=%02X\n",
+				readb(ti->srb), readb(ti->srb + RETCODE_OFST));
+#endif
+		switch (readb(ti->srb)) {	/* SRB command check */
+		case XMIT_DIR_FRAME:{
+			unsigned char xmit_ret_code;
+			xmit_ret_code = readb(ti->srb + RETCODE_OFST);
+			if (xmit_ret_code == 0xff) break;
+			DPRINTK("error on xmit_dir_frame request: %02X\n",
+								xmit_ret_code);
+			if (ti->current_skb) {
+				dev_kfree_skb_irq(ti->current_skb);
+				ti->current_skb = NULL;
 			}
-			check_reason += ti->sram;
-			SET_PAGE(check_reason_page);
-
-			DPRINTK("Adapter check interrupt\n");
-			DPRINTK("8 reason bytes follow: ");
-			for(i=0; i<8; i++, check_reason++)
-				printk("%02X ", (int)isa_readb(check_reason));
-			printk("\n");
-
-			isa_writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-			isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
-
-		} else if (isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
-				 & (TCR_INT | ERR_INT | ACCESS_INT)) {
+			/*dev->tbusy = 0;*/
+			netif_wake_queue(dev);
+			if (ti->readlog_pending)
+				ibmtr_readlog(dev);
+			break;
+		}
+		case XMIT_UI_FRAME:{
+			unsigned char xmit_ret_code;
 
-			DPRINTK("adapter error: ISRP_EVEN : %02x\n",
-				(int)isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN));
-			isa_writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
-			       ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
-			isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
-
-		} else if (status
-			   & (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) {
-			/* SRB, ASB, ARB or SSB response */
+			xmit_ret_code = readb(ti->srb + RETCODE_OFST);
+			if (xmit_ret_code == 0xff) break;
+			DPRINTK("error on xmit_ui_frame request: %02X\n",
+								xmit_ret_code);
+			if (ti->current_skb) {
+				dev_kfree_skb_irq(ti->current_skb);
+				ti->current_skb = NULL;
+			}
+			netif_wake_queue(dev);
+			if (ti->readlog_pending)
+				ibmtr_readlog(dev);
+			break;
+		}
+		case DIR_OPEN_ADAPTER:
+			dir_open_adapter(dev);
+			break;
+		case DLC_OPEN_SAP:
+			if (readb(ti->srb + RETCODE_OFST)) {
+				DPRINTK("open_sap failed: ret_code = %02X, "
+					"retrying\n",
+					(int) readb(ti->srb + RETCODE_OFST));
+				ti->open_action = REOPEN;
+				ibmtr_reset_timer(&(ti->tr_timer), dev);
+				break;
+			}
+			ti->exsap_station_id = readw(ti->srb + STATION_ID_OFST);
+			ti->sap_status = OPEN;/* TR adapter is now available */
+			if (ti->open_mode==MANUAL){
+				wake_up(&ti->wait_for_reset);
+				break;
+			}
+			netif_wake_queue(dev);
+			dev->flags |= IFF_RUNNING;/*BMS 12/2000*/
+			break;
+		case DIR_INTERRUPT:
+		case DIR_MOD_OPEN_PARAMS:
+		case DIR_SET_GRP_ADDR:
+		case DIR_SET_FUNC_ADDR:
+		case DLC_CLOSE_SAP:
+			if (readb(ti->srb + RETCODE_OFST))
+				DPRINTK("error on %02X: %02X\n",
+					(int) readb(ti->srb + COMMAND_OFST),
+					(int) readb(ti->srb + RETCODE_OFST));
+			break;
+		case DIR_READ_LOG:
+			if (readb(ti->srb + RETCODE_OFST)){
+				DPRINTK("error on dir_read_log: %02X\n",
+					(int) readb(ti->srb + RETCODE_OFST));
+				netif_wake_queue(dev);
+				break;
+			}
+#if IBMTR_DEBUG_MESSAGES
 
-			if (status & SRB_RESP_INT) { /* SRB response */
-           		        SET_PAGE(ti->srb_page);
+#define LINE_ERRORS_OFST                 0
+#define INTERNAL_ERRORS_OFST             1
+#define BURST_ERRORS_OFST                2
+#define AC_ERRORS_OFST                   3
+#define ABORT_DELIMITERS_OFST            4
+#define LOST_FRAMES_OFST                 6
+#define RECV_CONGEST_COUNT_OFST          7
+#define FRAME_COPIED_ERRORS_OFST         8
+#define FREQUENCY_ERRORS_OFST            9
+#define TOKEN_ERRORS_OFST               10
+
+			DPRINTK("Line errors %02X, Internal errors %02X, "
+			"Burst errors %02X\n" "A/C errors %02X, "
+			"Abort delimiters %02X, Lost frames %02X\n"
+			"Receive congestion count %02X, "
+			"Frame copied errors %02X\nFrequency errors %02X, "
+			"Token errors %02X\n",
+			(int) readb(ti->srb + LINE_ERRORS_OFST),
+			(int) readb(ti->srb + INTERNAL_ERRORS_OFST),
+			(int) readb(ti->srb + BURST_ERRORS_OFST),
+			(int) readb(ti->srb + AC_ERRORS_OFST),
+			(int) readb(ti->srb + ABORT_DELIMITERS_OFST),
+			(int) readb(ti->srb + LOST_FRAMES_OFST),
+			(int) readb(ti->srb + RECV_CONGEST_COUNT_OFST),
+			(int) readb(ti->srb + FRAME_COPIED_ERRORS_OFST),
+			(int) readb(ti->srb + FREQUENCY_ERRORS_OFST),
+			(int) readb(ti->srb + TOKEN_ERRORS_OFST));
+#endif
+			netif_wake_queue(dev);
+			break;
+		default:
+			DPRINTK("Unknown command %02X encountered\n",
+						(int) readb(ti->srb));
+        	}	/* end switch SRB command check */
+		writeb(~SRB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
+	}	/* if SRB response */
+	if (status & ASB_FREE_INT) {	/* ASB response */
+		SET_PAGE(ti->asb_page);
 #if TR_VERBOSE
- 				DPRINTK("SRB resp: cmd=%02X rsp=%02X\n",
-					isa_readb(ti->srb),
-					isa_readb(ti->srb + offsetof(struct srb_xmit, ret_code)));
-#endif
-
-				switch(isa_readb(ti->srb)) { /* SRB command check */
-
-				      case XMIT_DIR_FRAME: {
-					      unsigned char xmit_ret_code;
-
-					      xmit_ret_code=isa_readb(ti->srb + offsetof(struct srb_xmit, ret_code));
-					      if (xmit_ret_code != 0xff) {
-						      DPRINTK("error on xmit_dir_frame request: %02X\n",
-							      xmit_ret_code);
-						      if (ti->current_skb) {
-							      dev_kfree_skb_irq(ti->current_skb);
-							      ti->current_skb=NULL;
-						      }
-						      netif_wake_queue(dev);
-						      if (ti->readlog_pending) ibmtr_readlog(dev);
-					      }
-				      }
-				      break;
-
-				      case XMIT_UI_FRAME: {
-					      unsigned char xmit_ret_code;
-
-					      xmit_ret_code=isa_readb(ti->srb + offsetof(struct srb_xmit, ret_code));
-					      if (xmit_ret_code != 0xff) {
-						      DPRINTK("error on xmit_ui_frame request: %02X\n",
-							      xmit_ret_code);
-						      if (ti->current_skb) {
-							      dev_kfree_skb_irq(ti->current_skb);
-							      ti->current_skb=NULL;
-						      }
-						      netif_wake_queue(dev);
-						      if (ti->readlog_pending)
-						      		ibmtr_readlog(dev);
-					      }
-				      }
-				      break;
-
-				      case DIR_OPEN_ADAPTER: {
-					      unsigned char open_ret_code;
-					      __u16 open_error_code;
-
- 					      ti->srb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, srb_addr)));
- 					      ti->ssb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, ssb_addr)));
- 					      ti->arb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, arb_addr)));
- 					      ti->asb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, asb_addr)));
-					      if (ti->page_mask) {
-						ti->srb_page=(ti->srb>>8) & ti->page_mask;
-						ti->srb &= ~(ti->page_mask<<8);
-						ti->ssb_page=(ti->ssb>>8) & ti->page_mask;
-						ti->ssb &= ~(ti->page_mask<<8);
-						ti->arb_page=(ti->arb>>8) & ti->page_mask;
-						ti->arb &= ~(ti->page_mask<<8);
-						ti->asb_page=(ti->asb>>8) & ti->page_mask;
-						ti->asb &= ~(ti->page_mask<<8);
-					      }
-					      ti->srb+=ti->sram;
-					      ti->ssb+=ti->sram;
-					      ti->arb+=ti->sram;
-					      ti->asb+=ti->sram;
-
-					      ti->current_skb=NULL;
-
-					      open_ret_code = isa_readb(ti->init_srb +offsetof(struct srb_open_response, ret_code));
-					      open_error_code = ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, error_code)));
-
-					      if (open_ret_code==7) {
-
-						      if (!ti->auto_ringspeedsave && (open_error_code==0x24)) {
-							      DPRINTK("Open failed: Adapter speed must match ring "
-								      "speed if Automatic Ring Speed Save is disabled.\n");
-							      ti->open_status=FAILURE;
-							      wake_up(&ti->wait_for_reset);
-						      } else if (open_error_code==0x24)
-							      DPRINTK("Retrying open to adjust to ring speed.\n");
-						      else if ((open_error_code==0x2d) && ti->auto_ringspeedsave)
-							      DPRINTK("No signal detected for Auto Speed Detection.\n");
-						      else if (open_error_code==0x11)
-						      {
-							      if (ti->retry_count--) 
-								      DPRINTK("Ring broken/disconnected, retrying...\n");
-							      else {
-								      DPRINTK("Ring broken/disconnected, open failed.\n");
-								      ti->open_status = FAILURE;
-							      }
-						      }
-						      else DPRINTK("Unrecoverable error: error code = %04x.\n",
-								   open_error_code);
-
-					      } else if (!open_ret_code) {
-#if !TR_NEWFORMAT
-						      DPRINTK("board opened...\n");
-#else
-						      DPRINTK("Adapter initialized and opened.\n");
+		DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb));
 #endif
-						      isa_writeb(~(SRB_RESP_INT),
-							     ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-						      isa_writeb(~(CMD_IN_SRB),
-							     ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
-						      open_sap(EXTENDED_SAP,dev);
-
-						      /* YdW probably hates me */
-						      goto skip_reset;
-					      } else
-						      DPRINTK("open failed: ret_code = %02X, retrying\n",
-							      open_ret_code);
-
-					      if (ti->open_status != FAILURE) {
-						      ibmtr_reset_timer(&(ti->tr_timer), dev);
-					      }
-
-				      }
-				      break;
-
-				      case DIR_CLOSE_ADAPTER:
-					wake_up(&ti->wait_for_tok_int);
-					break;
-
-				      case DLC_OPEN_SAP:
-					if (isa_readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) {
-						DPRINTK("open_sap failed: ret_code = %02X,retrying\n",
-							(int)isa_readb(ti->srb+offsetof(struct dlc_open_sap, ret_code)));
-						ibmtr_reset_timer(&(ti->tr_timer), dev);
-					} else {
-						ti->exsap_station_id=
-							isa_readw(ti->srb+offsetof(struct dlc_open_sap, station_id));
-						ti->open_status=SUCCESS; /* TR adapter is now available */
-						wake_up(&ti->wait_for_reset);
-					}
-					break;
-
-				      case DIR_INTERRUPT:
-				      case DIR_MOD_OPEN_PARAMS:
-				      case DIR_SET_GRP_ADDR:
-				      case DIR_SET_FUNC_ADDR:
-				      case DLC_CLOSE_SAP:
-					if (isa_readb(ti->srb+offsetof(struct srb_interrupt, ret_code)))
-						DPRINTK("error on %02X: %02X\n",
-							(int)isa_readb(ti->srb+offsetof(struct srb_interrupt, command)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_interrupt, ret_code)));
-					break;
-
-				      case DIR_READ_LOG:
-					if (isa_readb(ti->srb+offsetof(struct srb_read_log, ret_code)))
-						DPRINTK("error on dir_read_log: %02X\n",
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log, ret_code)));
-					else
-					    if (IBMTR_DEBUG_MESSAGES) {
-						DPRINTK(
-							"Line errors %02X, Internal errors %02X, Burst errors %02X\n"
-							"A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n"
-							"Receive congestion count %02X, Frame copied errors %02X\n"
-							"Frequency errors %02X, Token errors %02X\n",
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    line_errors)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    internal_errors)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    burst_errors)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log, A_C_errors)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    abort_delimiters)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    lost_frames)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-												    recv_congest_count)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    frame_copied_errors)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-										    frequency_errors)),
-							(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
-												    token_errors)));
-					    }
-					netif_wake_queue(dev);
-					break;
-
-				      default:
-					DPRINTK("Unknown command %02X encountered\n",
-						(int)isa_readb(ti->srb));
-
-				} /* SRB command check */
 
-				isa_writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
-				isa_writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
+		switch (readb(ti->asb)) {	/* ASB command check */
+		case REC_DATA:
+		case XMIT_UI_FRAME:
+		case XMIT_DIR_FRAME:
+			break;
+		default:
+			DPRINTK("unknown command in asb %02X\n",
+						(int) readb(ti->asb));
+		}	/* switch ASB command check */
+		if (readb(ti->asb + 2) != 0xff)	/* checks ret_code */
+			DPRINTK("ASB error %02X in cmd %02X\n",
+				(int) readb(ti->asb + 2), (int) readb(ti->asb));
+		writeb(~ASB_FREE_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
+	}	/* if ASB response */
 
-			  skip_reset:;
-			} /* SRB response */
+#define STATUS_OFST             6
+#define NETW_STATUS_OFST        6
 
-			if (status & ASB_FREE_INT) { /* ASB response */
-			        SET_PAGE(ti->asb_page);
+	if (status & ARB_CMD_INT) {	/* ARB response */
+		SET_PAGE(ti->arb_page);
 #if TR_VERBOSE
- 				DPRINTK("ASB resp: cmd=%02X\n", isa_readb(ti->asb));
- #endif
-
-				switch(isa_readb(ti->asb)) { /* ASB command check */
-
-				      case REC_DATA:
-				      case XMIT_UI_FRAME:
-				      case XMIT_DIR_FRAME:
-					break;
-
-				      default:
-					DPRINTK("unknown command in asb %02X\n",
-						(int)isa_readb(ti->asb));
-
-				} /* ASB command check */
-
-				if (isa_readb(ti->asb+2)!=0xff) /* checks ret_code */
-				    DPRINTK("ASB error %02X in cmd %02X\n",
-					    (int)isa_readb(ti->asb+2),(int)isa_readb(ti->asb));
-				isa_writeb(~ASB_FREE_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-
-			} /* ASB response */
-
-			if (status & ARB_CMD_INT) { /* ARB response */
-            		        SET_PAGE(ti->arb_page);
-#if TR_VERBOSE 
- 				DPRINTK("ARB resp: cmd=%02X rsp=%02X\n",
- 					isa_readb(ti->arb),
- 					isa_readb(ti->arb + offsetof(struct arb_dlc_status, status)));
+		DPRINTK("ARB resp: cmd=%02X\n", readb(ti->arb));
 #endif
 
-				switch (isa_readb(ti->arb)) { /* ARB command check */
-
-				      case DLC_STATUS:
-					DPRINTK("DLC_STATUS new status: %02X on station %02X\n",
-						ntohs(isa_readw(ti->arb + offsetof(struct arb_dlc_status, status))),
-						ntohs(isa_readw(ti->arb
-									    +offsetof(struct arb_dlc_status, station_id))));
-					break;
-
-				      case REC_DATA:
-					tr_rx(dev);
-					break;
-
-				      case RING_STAT_CHANGE: {
-					      unsigned short ring_status;
-
-					      ring_status=ntohs(isa_readw(ti->arb
-								      +offsetof(struct arb_ring_stat_change, ring_status)));
-
-					      if (ring_status & (SIGNAL_LOSS | LOBE_FAULT)) {
-
-						      DPRINTK("Signal loss/Lobe fault\n");
-						      DPRINTK("We try to reopen the adapter.\n");
-						      ibmtr_reset_timer(&(ti->tr_timer), dev);
-					      } else if (ring_status & (HARD_ERROR | XMIT_BEACON
-											| AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER))
-						      DPRINTK("New ring status: %02X\n", ring_status);
-
-					      if (ring_status & LOG_OVERFLOW) {
-						      if (netif_queue_stopped(dev))
-                                                              ti->readlog_pending = 1;
-						      else
-                                                              ibmtr_readlog(dev);
-					      }
-				      }
-				      break;
-
-				      case XMIT_DATA_REQ:
-					tr_tx(dev);
-					break;
-
-				      default:
-					DPRINTK("Unknown command %02X in arb\n",
-						(int)isa_readb(ti->arb));
-					break;
-
-				} /* ARB command check */
-
-				isa_writeb(~ARB_CMD_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-				isa_writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-			} /* ARB response */
-
-			if (status & SSB_RESP_INT) { /* SSB response */
-				unsigned char retcode;
- 				SET_PAGE(ti->ssb_page);
+		switch (readb(ti->arb)) {	/* ARB command check */
+		case DLC_STATUS:
+			DPRINTK("DLC_STATUS new status: %02X on station %02X\n",
+				ntohs(readw(ti->arb + STATUS_OFST)),
+				ntohs(readw(ti->arb+ STATION_ID_OFST)));
+			break;
+		case REC_DATA:
+			tr_rx(dev);
+			break;
+		case RING_STAT_CHANGE:{
+			unsigned short ring_status;
+			ring_status= ntohs(readw(ti->arb + NETW_STATUS_OFST));
+			if (ibmtr_debug_trace & TRC_INIT)
+				DPRINTK("Ring Status Change...(0x%x)\n",
+								ring_status);
+			if(ring_status& (REMOVE_RECV|AUTO_REMOVAL|LOBE_FAULT)){
+				netif_stop_queue(dev);
+				dev->flags &= ~IFF_RUNNING;/*not typical Linux*/
+				DPRINTK("Remove received, or Auto-removal error"
+					", or Lobe fault\n");
+				DPRINTK("We'll try to reopen the closed adapter"
+					" after a %d second delay.\n",
+						TR_RETRY_INTERVAL/HZ);
+				/*I was confused: I saw the TR reopening but */
+				/*forgot:with an RJ45 in an RJ45/ICS adapter */
+				/*but adapter not in the ring, the TR will   */
+				/* open, and then soon close and come here.  */
+				ti->open_mode = AUTOMATIC;
+				ti->open_status = CLOSED; /*12/2000 BMS*/
+				ti->open_action = REOPEN;
+				ibmtr_reset_timer(&(ti->tr_timer), dev);
+			} else if (ring_status & LOG_OVERFLOW) {
+				if(netif_queue_stopped(dev))
+					ti->readlog_pending = 1;
+				else
+					ibmtr_readlog(dev);
+			}
+			break;
+          	}
+		case XMIT_DATA_REQ:
+			tr_tx(dev);
+			break;
+		default:
+			DPRINTK("Unknown command %02X in arb\n",
+						(int) readb(ti->arb));
+			break;
+		}	/* switch ARB command check */
+		writeb(~ARB_CMD_INT, ti->mmio+ ACA_OFFSET+ACA_RESET + ISRP_ODD);
+		writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	}	/* if ARB response */
+	if (status & SSB_RESP_INT) {	/* SSB response */
+		unsigned char retcode;
+		SET_PAGE(ti->ssb_page);
 #if TR_VERBOSE
- 				DPRINTK("SSB resp: cmd=%02X rsp=%02X\n",
- 					isa_readb(ti->ssb), isa_readb(ti->ssb+2));
+		DPRINTK("SSB resp: cmd=%02X rsp=%02X\n",
+				readb(ti->ssb), readb(ti->ssb + 2));
 #endif
-				switch (isa_readb(ti->ssb)) { /* SSB command check */
-				      
-				      case XMIT_DIR_FRAME:
-				      case XMIT_UI_FRAME:
-					retcode = isa_readb(ti->ssb+2);
-					if (retcode && (retcode != 0x22)) /* checks ret_code */
-						DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
-							(int)retcode, (int)isa_readb(ti->ssb+6));
-					else ti->tr_stats.tx_packets++;
-					break;
-
-				      case XMIT_XID_CMD:
-					DPRINTK("xmit xid ret_code: %02X\n", (int)isa_readb(ti->ssb+2));
-                                        break;
-
-				      default:
-					DPRINTK("Unknown command %02X in ssb\n", (int)isa_readb(ti->ssb));
-
-				} /* SSB command check */
-
-				isa_writeb(~SSB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-				isa_writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-			} /* SSB response */
-
-		}	 /* SRB, ARB, ASB or SSB response */
-
-		isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-		break;
 
-	      case FIRST_INT:
-		initial_tok_int(dev);
-		break;
-
-	      default:
-		DPRINTK("Unexpected interrupt from tr adapter\n");
-
-	}
-#ifdef PCMCIA
- return_point:
-#endif
+		switch (readb(ti->ssb)) {	/* SSB command check */
+		case XMIT_DIR_FRAME:
+		case XMIT_UI_FRAME:
+			retcode = readb(ti->ssb + 2);
+			if (retcode && (retcode != 0x22))/* checks ret_code */
+				DPRINTK("xmit ret_code: %02X xmit error code: "
+					"%02X\n",
+					(int)retcode, (int)readb(ti->ssb + 6));
+			else
+				ti->tr_stats.tx_packets++;
+			break;
+		case XMIT_XID_CMD:
+			DPRINTK("xmit xid ret_code: %02X\n",
+						(int) readb(ti->ssb + 2));
+		default:
+			DPRINTK("Unknown command %02X in ssb\n",
+						(int) readb(ti->ssb));
+		}	/* SSB command check */
+		writeb(~SSB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD);
+		writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	}	/* if SSB response */
 #ifdef ENABLE_PAGING
- 	isa_writeb(save_srpr, ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN);
+	writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
 #endif
-
+	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
 	spin_unlock(&(ti->lock));
-}
+}				/*tok_interrupt */
+
+/*****************************************************************************/
+
+#define INIT_STATUS_OFST        1
+#define INIT_STATUS_2_OFST      2
+#define ENCODED_ADDRESS_OFST    8
 
 static void initial_tok_int(struct net_device *dev)
 {
 
-	__u32 encoded_addr;
-	__u32 hw_encoded_addr;
+	__u32 encoded_addr, hw_encoded_addr;
 	struct tok_info *ti;
-	ti=(struct tok_info *) dev->priv;
+        unsigned char init_status; /*BMS 12/2000*/
 
-	ti->do_tok_int=NOT_FIRST;
+	ti = (struct tok_info *) dev->priv;
 
-#ifndef TR_NEWFORMAT
-	DPRINTK("Initial tok int received\n");
-#endif
+	ti->do_tok_int = NOT_FIRST;
 
 	/* we assign the shared-ram address for ISA devices */
-	if(!ti->sram) {
-		isa_writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
-		ti->sram=((__u32)ti->sram_base << 12);
-	}
- 	ti->init_srb=ntohs((unsigned short)isa_readw(ti->mmio+ ACA_OFFSET + WRBR_EVEN));
+	writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
+#ifndef PCMCIA
+        ti->sram_virt = (u32)ioremap(((__u32)ti->sram_base << 12), ti->avail_shared_ram);
+#endif
+	ti->init_srb = ntohs(readw(ti->mmio + ACA_OFFSET + WRBR_EVEN));
 	if (ti->page_mask) {
-	  ti->init_srb_page=(ti->init_srb>>8)&ti->page_mask;
-	  ti->init_srb &= ~(ti->page_mask<<8);
+		ti->init_srb_page = (ti->init_srb >> 8) & ti->page_mask;
+		ti->init_srb &= ~(ti->page_mask << 8);
+	}
+	ti->init_srb += ti->sram_virt;
+	if (ti->page_mask && ti->avail_shared_ram == 127) {
+		int last_512 = 0xfe00, i;
+		int last_512_page=0;
+		last_512_page=(last_512>>8)&ti->page_mask;
+		last_512 &= ~(ti->page_mask << 8);
+		/* initialize high section of ram (if necessary) */
+		SET_PAGE(last_512_page);
+		for (i = 0; i < 512; i++)
+			writeb(0, ti->sram_virt + last_512 + i);
 	}
-	ti->init_srb+=ti->sram;
-	
-	if (ti->avail_shared_ram == 127) {
-	  int i;
-	  int last_512=0xfe00;
- 	  if (ti->page_mask) {
-	    last_512 &= ~(ti->page_mask<<8);
-	  }
-	  /*  initialize high section of ram (if necessary) */
-	  SET_PAGE(0xc0);
-	  for (i=0; i<512; i++) {
-	    isa_writeb(0,ti->sram+last_512+i);
-	  }
-	}  
 	SET_PAGE(ti->init_srb_page);
 
-	dev->mem_start = ti->sram;
-	dev->mem_end = ti->sram + (ti->mapped_ram_size<<9) - 1;
-
 #if TR_VERBOSE
 	{
-		int i;
-		DPRINTK("init_srb(%lx):", (long)ti->init_srb);
-		for (i=0;i<17;i++) printk("%02X ", (int)isa_readb(ti->init_srb+i));
-		printk("\n");
-	}
-#endif
-
-	hw_encoded_addr = isa_readw(ti->init_srb
-				+ offsetof(struct srb_init_response, encoded_address));
-
-#if !TR_NEWFORMAT
-	DPRINTK("srb_init_response->encoded_address: %04X\n", hw_encoded_addr);
-	DPRINTK("ntohs(srb_init_response->encoded_address): %04X\n",
-		ntohs(hw_encoded_addr));
-#endif
-
-	encoded_addr=(ti->sram + ntohs(hw_encoded_addr));
-	ti->ring_speed = isa_readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4;
-#if !TR_NEWFORMAT
-	DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr,
-		ntohs(hw_encoded_addr), encoded_addr);
-#else
-	DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
-		ti->ring_speed, ti->sram);
-#endif
-
-	ti->auto_ringspeedsave=isa_readb(ti->init_srb
-				     +offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE;
-
-#if !TR_NEWFORMAT
-	for(i=0;i<TR_ALEN;i++) {
-		dev->dev_addr[i]=isa_readb(encoded_addr + i);
-		printk("%02X%s", dev->dev_addr[i], (i==TR_ALEN-1) ? "" : ":" );
-	}
-	printk("\n");
-#endif
-
-	tok_open_adapter((unsigned long)dev);
-}
-
-static int tok_init_card(struct net_device *dev)
-{
-	struct tok_info *ti;
-	short PIOaddr;
-	unsigned long i;
-	PIOaddr = dev->base_addr;
-	ti=(struct tok_info *) dev->priv;
-
-	/* Special processing for first interrupt after reset */
-	ti->do_tok_int=FIRST_INT;
-
-	/* Reset adapter */
-	netif_stop_queue(dev);
-
-	isa_writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
-
-#if !TR_NEWFORMAT
-	DPRINTK("resetting card\n");
-#endif
-
-	outb(0, PIOaddr+ADAPTRESET);
-	for (i=jiffies+TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */
-	outb(0,PIOaddr+ADAPTRESETREL);
-#ifdef ENABLE_PAGING
-	if(ti->page_mask)
-		isa_writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
-#endif
-
-#if !TR_NEWFORMAT
-	DPRINTK("card reset\n");
-#endif
-
-	ti->open_status=IN_PROGRESS;
-	isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-	return 0;
-}
-
-static void open_sap(unsigned char type,struct net_device *dev)
-{
 	int i;
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-
-	SET_PAGE(ti->srb_page);
-	for (i=0; i<sizeof(struct dlc_open_sap); i++)
-		isa_writeb(0, ti->srb+i);
 
-	isa_writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command));
-	isa_writew(htons(MAX_I_FIELD),
-	       ti->srb + offsetof(struct dlc_open_sap, max_i_field));
-	isa_writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY,
-	       ti->srb + offsetof(struct dlc_open_sap, sap_options));
-	isa_writeb(SAP_OPEN_STATION_CNT,
-	       ti->srb + offsetof(struct dlc_open_sap, station_count));
-	isa_writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value));
-
-	isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-
-}
-
-void tok_open_adapter(unsigned long dev_addr)
-{
-
-	struct net_device *dev=(struct net_device *)dev_addr;
-	struct tok_info *ti;
-	int i;
-
-	ti=(struct tok_info *) dev->priv;
-
-#if !TR_NEWFORMAT
-	DPRINTK("now opening the board...\n");
+	DPRINTK("ti->init_srb_page=0x%x\n", ti->init_srb_page);
+	DPRINTK("init_srb(%x):", (ti->init_srb) );
+	for (i = 0; i < 20; i++)
+		printk("%02X ", (int) readb(ti->init_srb + i));
+	printk("\n");
+	}
 #endif
 
-	isa_writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
-	isa_writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
+	hw_encoded_addr = readw(ti->init_srb + ENCODED_ADDRESS_OFST);
+	encoded_addr = ntohs(hw_encoded_addr);
+        init_status= /*BMS 12/2000 check for shallow mode possibility (Turbo)*/
+	readb(ti->init_srb+offsetof(struct srb_init_response,init_status));
+	/*printk("Initial interrupt: init_status= 0x%02x\n",init_status);*/
+	ti->ring_speed = init_status & 0x01 ? 16 : 4;
+	DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
+				ti->ring_speed, (unsigned int)dev->mem_start);
+	ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE;
 
-	for (i=0; i<sizeof(struct dir_open_adapter); i++)
-		isa_writeb(0, ti->init_srb+i);
+        if (ti->open_mode == MANUAL)	wake_up(&ti->wait_for_reset);
+	else				tok_open_adapter((unsigned long)dev);
+        
+} /*initial_tok_int() */
 
-	isa_writeb(DIR_OPEN_ADAPTER,
-	       ti->init_srb + offsetof(struct dir_open_adapter, command));
-	isa_writew(htons(OPEN_PASS_BCON_MAC),
-	       ti->init_srb + offsetof(struct dir_open_adapter, open_options));
-	if (ti->ring_speed == 16) {
-		isa_writew(htons(ti->dhb_size16mb),
-		       ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
-		isa_writew(htons(ti->rbuf_cnt16),
-		       ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
-		isa_writew(htons(ti->rbuf_len16),
-		       ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
-	} else {
-		isa_writew(htons(ti->dhb_size4mb),
-		       ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
-		isa_writew(htons(ti->rbuf_cnt4),
-		       ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
-		isa_writew(htons(ti->rbuf_len4),
-		       ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
-	}
-	isa_writeb(NUM_DHB, /* always 2 */ 
-	       ti->init_srb + offsetof(struct dir_open_adapter, num_dhb));
-	isa_writeb(DLC_MAX_SAP,
-	       ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap));
-	isa_writeb(DLC_MAX_STA,
-	       ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta));
-
-	ti->srb=ti->init_srb; /* We use this one in the interrupt handler */
-	ti->srb_page=ti->init_srb_page;
-	DPRINTK("Opend adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n",
-		isa_readb(ti->init_srb+offsetof(struct dir_open_adapter,num_dhb)),
-		ntohs(isa_readw(ti->init_srb+offsetof(struct dir_open_adapter,dhb_length))),
-		ntohs(isa_readw(ti->init_srb+offsetof(struct dir_open_adapter,num_rcv_buf))),
-		ntohs(isa_readw(ti->init_srb+offsetof(struct dir_open_adapter,rcv_buf_len))) );
+/*****************************************************************************/
 
-	isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-	isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+#define CMD_CORRELATE_OFST      1
+#define DHB_ADDRESS_OFST        6
 
-}
+#define FRAME_LENGTH_OFST       6
+#define HEADER_LENGTH_OFST      8
+#define RSAP_VALUE_OFST         9
 
 static void tr_tx(struct net_device *dev)
 {
-	struct tok_info *ti=(struct tok_info *) dev->priv;
-	struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data;
+	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data;
 	unsigned int hdr_len;
-	__u32 dhb;
+	__u32 dhb=0,dhb_base;
 	unsigned char xmit_command;
-	int i;
-	struct trllc	*llc;
-	struct srb_xmit  xsrb;
-	__u8  dhb_page=0;
-	__u8  llc_ssap;
+	int i,dhb_len=0x4000,src_len,src_offset;
+	struct trllc *llc;
+	struct srb_xmit xsrb;
+	__u8 dhb_page = 0;
+	__u8 llc_ssap;
 
 	SET_PAGE(ti->asb_page);
-	if (isa_readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF)
-		DPRINTK("ASB not free !!!\n");
 
-	/* in providing the transmit interrupts,
-	   is telling us it is ready for data and
-	   providing a shared memory address for us
-	   to stuff with data.  Here we compute the
-	   effective address where we will place data.*/
-        SET_PAGE(ti->arb_page);
- 	dhb=ntohs(isa_readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address)));
-        if (ti->page_mask) {
-	  dhb_page=(dhb >> 8) & ti->page_mask;
-	  dhb &= ~(ti->page_mask << 8);
-        }
-        dhb+=ti->sram;
-	
+	if (readb(ti->asb+RETCODE_OFST) != 0xFF) DPRINTK("ASB not free !!!\n");
+
+	/* in providing the transmit interrupts, is telling us it is ready for
+	   data and providing a shared memory address for us to stuff with data.
+	   Here we compute the effective address where we will place data.
+	*/
+	SET_PAGE(ti->arb_page);
+	dhb=dhb_base=ntohs(readw(ti->arb + DHB_ADDRESS_OFST));
+	if (ti->page_mask) {
+		dhb_page = (dhb_base >> 8) & ti->page_mask;
+		dhb=dhb_base & ~(ti->page_mask << 8);
+	}
+	dhb += ti->sram_virt;
+
 	/* Figure out the size of the 802.5 header */
-	if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */
-		hdr_len=sizeof(struct trh_hdr)-TR_MAXRIFLEN;
-	else 
-		hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8)
-			+sizeof(struct trh_hdr)-TR_MAXRIFLEN;
-
-	llc = (struct trllc *)(ti->current_skb->data + hdr_len);
-
-	llc_ssap=llc->ssap;
- 	SET_PAGE(ti->srb_page);
- 	isa_memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb));
- 	SET_PAGE(ti->asb_page);
- 	xmit_command=xsrb.command;
-	
-	isa_writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command));
-	isa_writew(xsrb.station_id,
-	       ti->asb + offsetof(struct asb_xmit_resp, station_id));
-	isa_writeb(llc_ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value));
- 	isa_writeb(xsrb.cmd_corr,
-	       ti->asb + offsetof(struct asb_xmit_resp, cmd_corr));
-	isa_writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code));
-
-	if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) {
-
-		isa_writew(htons(0x11),
-		       ti->asb + offsetof(struct asb_xmit_resp, frame_length));
-		isa_writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
-		SET_PAGE(dhb_page);
-		isa_writeb(AC, dhb);
-		isa_writeb(LLC_FRAME, dhb+1);
+	if (!(trhdr->saddr[0] & 0x80))	/* RIF present? */
+		hdr_len = sizeof(struct trh_hdr) - TR_MAXRIFLEN;
+	else
+		hdr_len = ((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK) >> 8)
+		    + sizeof(struct trh_hdr) - TR_MAXRIFLEN;
 
-		for (i=0; i<TR_ALEN; i++) isa_writeb((int)0x0FF, dhb+i+2);
-		for (i=0; i<TR_ALEN; i++) isa_writeb(0, dhb+i+TR_ALEN+2);
+	llc = (struct trllc *) (ti->current_skb->data + hdr_len);
 
-		isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-		return;
+	llc_ssap = llc->ssap;
+	SET_PAGE(ti->srb_page);
+	memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb));
+	SET_PAGE(ti->asb_page);
+	xmit_command = xsrb.command;
 
+	writeb(xmit_command, ti->asb + COMMAND_OFST);
+	writew(xsrb.station_id, ti->asb + STATION_ID_OFST);
+	writeb(llc_ssap, ti->asb + RSAP_VALUE_OFST);
+	writeb(xsrb.cmd_corr, ti->asb + CMD_CORRELATE_OFST);
+	writeb(0, ti->asb + RETCODE_OFST);
+	if ((xmit_command == XMIT_XID_CMD) || (xmit_command == XMIT_TEST_CMD)) {
+		writew(htons(0x11), ti->asb + FRAME_LENGTH_OFST);
+		writeb(0x0e, ti->asb + HEADER_LENGTH_OFST);
+		SET_PAGE(dhb_page);
+		writeb(AC, dhb);
+		writeb(LLC_FRAME, dhb + 1);
+		for (i = 0; i < TR_ALEN; i++)
+			writeb((int) 0x0FF, dhb + i + 2);
+		for (i = 0; i < TR_ALEN; i++)
+			writeb(0, dhb + i + TR_ALEN + 2);
+		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+		return;
 	}
-
 	/*
-	 *      the token ring packet is copied from sk_buff to the adapter
-	 *      buffer identified in the command data received with the interrupt.
+	 *    the token ring packet is copied from sk_buff to the adapter
+	 *    buffer identified in the command data received with the interrupt.
 	 */
-	isa_writeb(hdr_len, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
-	isa_writew(htons(ti->current_skb->len),
-	       ti->asb + offsetof(struct asb_xmit_resp, frame_length));
-
-	SET_PAGE(dhb_page);
-	isa_memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len);
-
-	isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-	ti->tr_stats.tx_bytes+=ti->current_skb->len;
+	writeb(hdr_len, ti->asb + HEADER_LENGTH_OFST);
+	writew(htons(ti->current_skb->len), ti->asb + FRAME_LENGTH_OFST);
+	src_len=ti->current_skb->len;
+	src_offset=0;
+	dhb=dhb_base;
+	while(1) {
+		if (ti->page_mask) {
+			dhb_page=(dhb >> 8) & ti->page_mask;
+			dhb=dhb & ~(ti->page_mask << 8);
+			dhb_len=0x4000-dhb; /* remaining size of this page */
+		}
+		dhb+=ti->sram_virt;
+		SET_PAGE(dhb_page);
+		if (src_len > dhb_len) {
+			memcpy_toio(dhb,&ti->current_skb->data[src_offset],
+					dhb_len);
+			src_len -= dhb_len;
+			src_offset += dhb_len;
+			dhb_base+=dhb_len;
+			dhb=dhb_base;
+			continue;
+		}
+		memcpy_toio(dhb, &ti->current_skb->data[src_offset], src_len);
+		break;
+	}
+	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	ti->tr_stats.tx_bytes += ti->current_skb->len;
 	dev_kfree_skb_irq(ti->current_skb);
-	ti->current_skb=NULL;
+	ti->current_skb = NULL;
 	netif_wake_queue(dev);
-	if (ti->readlog_pending) ibmtr_readlog(dev);
-}
+	if (ti->readlog_pending)
+		ibmtr_readlog(dev);
+}				/*tr_tx */
+
+/*****************************************************************************/
+
+
+#define RECEIVE_BUFFER_OFST     6
+#define LAN_HDR_LENGTH_OFST     8
+#define DLC_HDR_LENGTH_OFST     9
+
+#define DSAP_OFST               0
+#define SSAP_OFST               1
+#define LLC_OFST                2
+#define PROTID_OFST             3
+#define ETHERTYPE_OFST          6
 
 static void tr_rx(struct net_device *dev)
 {
-	struct tok_info *ti=(struct tok_info *) dev->priv;
+	struct tok_info *ti = (struct tok_info *) dev->priv;
 	__u32 rbuffer, rbufdata;
-	__u8  rbuffer_page=0;
+	__u8 rbuffer_page = 0;
 	__u32 llc;
 	unsigned char *data;
 	unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
+	unsigned char dlc_hdr_len;
 	struct sk_buff *skb;
 	unsigned int skb_size = 0;
-	int	IPv4_p = 0;
+	int IPv4_p = 0;
 	unsigned int chksum = 0;
 	struct iphdr *iph;
 	struct arb_rec_req rarb;
 
 	SET_PAGE(ti->arb_page);
- 	isa_memcpy_fromio(&rarb, ti->arb, sizeof(rarb));
- 	rbuffer=ntohs(rarb.rec_buf_addr)+2;
+	memcpy_fromio(&rarb, ti->arb, sizeof(rarb));
+	rbuffer = ntohs(rarb.rec_buf_addr) ;
 	if (ti->page_mask) {
-	  rbuffer_page=(rbuffer >> 8) & ti->page_mask;
-	  rbuffer &= ~(ti->page_mask<<8);
+		rbuffer_page = (rbuffer >> 8) & ti->page_mask;
+		rbuffer &= ~(ti->page_mask << 8);
 	}
-	rbuffer += ti->sram;
-	
+	rbuffer += ti->sram_virt;
+
 	SET_PAGE(ti->asb_page);
-	if(isa_readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF)
-		DPRINTK("ASB not free !!!\n");
 
-	isa_writeb(REC_DATA,
-	       ti->asb + offsetof(struct asb_rec, command));
-	isa_writew(rarb.station_id,
-	       ti->asb + offsetof(struct asb_rec, station_id));
-	isa_writew(rarb.rec_buf_addr,
-	       ti->asb + offsetof(struct asb_rec, rec_buf_addr));
+	if (readb(ti->asb + RETCODE_OFST) !=0xFF) DPRINTK("ASB not free !!!\n");
 
-	lan_hdr_len=rarb.lan_hdr_len;
+	writeb(REC_DATA, ti->asb + COMMAND_OFST);
+	writew(rarb.station_id, ti->asb + STATION_ID_OFST);
+	writew(rarb.rec_buf_addr, ti->asb + RECEIVE_BUFFER_OFST);
+
+	lan_hdr_len = rarb.lan_hdr_len;
+	if (lan_hdr_len > sizeof(struct trh_hdr)) {
+		DPRINTK("Linux cannot handle greater than 18 bytes RIF\n");
+		return;
+	}			/*BMS I added this above just to be very safe */
+	dlc_hdr_len = readb(ti->arb + DLC_HDR_LENGTH_OFST);
 	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
 
 	SET_PAGE(rbuffer_page);
-	llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
+	llc = (rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
 
 #if TR_VERBOSE
 	DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
-		(unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len);
-	DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %lx\n", llc,
-		ntohs(rarb.rec_buf_addr),
-		(long)ti->sram);
+	(__u32) offsetof(struct rec_buf, data), (unsigned int) lan_hdr_len);
+	DPRINTK("llc: %08X rec_buf_addr: %04X dev->mem_start: %lX\n",
+		llc, ntohs(rarb.rec_buf_addr), dev->mem_start);
 	DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, "
 		"ethertype: %04X\n",
-		(int)isa_readb(llc + offsetof(struct trllc, dsap)),
-		(int)isa_readb(llc + offsetof(struct trllc, ssap)),
-		(int)isa_readb(llc + offsetof(struct trllc, llc)),
-		(int)isa_readb(llc + offsetof(struct trllc, protid)),
-		(int)isa_readb(llc + offsetof(struct trllc, protid)+1),
-		(int)isa_readb(llc + offsetof(struct trllc, protid)+2),
-		(int)isa_readw(llc + offsetof(struct trllc, ethertype)));
-#endif
-	if (isa_readb(llc + offsetof(struct trllc, llc))!=UI_CMD) {
-                SET_PAGE(ti->asb_page);
-		isa_writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
+		(int) readb(llc + DSAP_OFST), (int) readb(llc + SSAP_OFST),
+		(int) readb(llc + LLC_OFST), (int) readb(llc + PROTID_OFST),
+		(int) readb(llc+PROTID_OFST+1),(int)readb(llc+PROTID_OFST + 2),
+		(int) ntohs(readw(llc + ETHERTYPE_OFST)));
+#endif
+	if (readb(llc + offsetof(struct trllc, llc)) != UI_CMD) {
+		SET_PAGE(ti->asb_page);
+		writeb(DATA_LOST, ti->asb + RETCODE_OFST);
 		ti->tr_stats.rx_dropped++;
-		isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
 		return;
 	}
-
 	length = ntohs(rarb.frame_len);
-	if ((isa_readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) &&
-       	    (isa_readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) &&
-		(length>=hdr_len)) {
-       		IPv4_p = 1;
-       	}
-
+	if (readb(llc + DSAP_OFST) == EXTENDED_SAP &&
+	   readb(llc + SSAP_OFST) == EXTENDED_SAP &&
+		length >= hdr_len)	IPv4_p = 1;
 #if TR_VERBOSE
-       	if (!IPv4_p){
+#define SADDR_OFST	8
+#define DADDR_OFST	2
 
-       		__u32 trhhdr;
+	if (!IPv4_p) {
 
-       		trhhdr=(rbuffer+offsetof(struct rec_buf,data));
+		__u32 trhhdr;
 
-       		DPRINTK("Probably non-IP frame received.\n");
-       		DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X "
-       			"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
-       			(int)isa_readb(llc + offsetof(struct trllc, ssap)),
-       			(int)isa_readb(llc + offsetof(struct trllc, dsap)),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+1),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+2),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+3),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+4),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+5),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+1),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+2),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+3),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+4),
-       			(int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+5));
-       	}
-#endif
-
-       	skb_size = length;
- 
-       	if (!(skb=dev_alloc_skb(skb_size))) {
-       		DPRINTK("out of memory. frame dropped.\n");
-       		ti->tr_stats.rx_dropped++;
+		trhhdr = (rbuffer + offsetof(struct rec_buf, data));
+
+		DPRINTK("Probably non-IP frame received.\n");
+		DPRINTK("ssap: %02X dsap: %02X "
+			"saddr: %02X:%02X:%02X:%02X:%02X:%02X "
+			"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
+			readb(llc + SSAP_OFST), readb(llc + DSAP_OFST),
+			readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1),
+			readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3),
+			readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5),
+			readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1),
+			readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3),
+			readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5));
+	}
+#endif
+
+	/*BMS handle the case she comes in with few hops but leaves with many */
+        skb_size=length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc);
+
+	if (!(skb = dev_alloc_skb(skb_size))) {
+		DPRINTK("out of memory. frame dropped.\n");
+		ti->tr_stats.rx_dropped++;
 		SET_PAGE(ti->asb_page);
-       		isa_writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
-       		isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-       		return;
-       	}
-
-      	skb_put(skb, length);
-	skb_reserve(skb, sizeof(struct trh_hdr)-lan_hdr_len+sizeof(struct trllc));
-       	skb->dev=dev;
-       	data=skb->data;
-	rbuffer_len=ntohs(isa_readw(rbuffer + offsetof(struct rec_buf, buf_len)));
-	rbufdata = rbuffer + offsetof(struct rec_buf,data);
+		writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
+		writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+		return;
+	}
+	/*BMS again, if she comes in with few but leaves with many */
+	skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len);
+	skb_put(skb, length);
+	skb->dev = dev;
+	data = skb->data;
+	rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
+	rbufdata = rbuffer + offsetof(struct rec_buf, data);
 
 	if (IPv4_p) {
-                /* Copy the headers without checksumming */
-		isa_memcpy_fromio(data, rbufdata, hdr_len);
+		/* Copy the headers without checksumming */
+		memcpy_fromio(data, rbufdata, hdr_len);
 
 		/* Watch for padded packets and bogons */
-		iph=(struct iphdr*)(data + lan_hdr_len + sizeof(struct trllc));
+		iph= (struct iphdr *)(data+ lan_hdr_len + sizeof(struct trllc));
 		ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
 		length -= hdr_len;
 		if ((ip_len <= length) && (ip_len > 7))
@@ -1751,107 +1769,123 @@
 		data += hdr_len;
 		rbuffer_len -= hdr_len;
 		rbufdata += hdr_len;
-        }
-
+	}
 	/* Copy the payload... */
+#define BUFFER_POINTER_OFST	2
+#define BUFFER_LENGTH_OFST      6
 	for (;;) {
+		if (ibmtr_debug_trace&TRC_INITV && length < rbuffer_len)
+			DPRINTK("CURIOUS, length=%d < rbuffer_len=%d\n",
+						length,rbuffer_len);
 		if (IPv4_p)
-			chksum = csum_partial_copy_nocheck(bus_to_virt(rbufdata), data,
-						   length < rbuffer_len ? length : rbuffer_len,
-						   chksum);
+			chksum=csum_partial_copy_nocheck((void*)rbufdata,
+			    data,length<rbuffer_len?length:rbuffer_len,chksum);
 		else
-			isa_memcpy_fromio(data, rbufdata, rbuffer_len);
-		rbuffer = ntohs(isa_readw(rbuffer));
+			memcpy_fromio(data, rbufdata, rbuffer_len);
+		rbuffer = ntohs(readw(rbuffer+BUFFER_POINTER_OFST)) ;
 		if (!rbuffer)
 			break;
+		rbuffer -= 2;
 		length -= rbuffer_len;
 		data += rbuffer_len;
 		if (ti->page_mask) {
-		  rbuffer_page=(rbuffer>>8) & ti->page_mask;
-		  rbuffer &= ~(ti->page_mask << 8);
+			rbuffer_page = (rbuffer >> 8) & ti->page_mask;
+			rbuffer &= ~(ti->page_mask << 8);
 		}
-		rbuffer += ti->sram;
+		rbuffer += ti->sram_virt;
 		SET_PAGE(rbuffer_page);
-		rbuffer_len = ntohs(isa_readw(rbuffer + offsetof(struct rec_buf, buf_len)));
+		rbuffer_len = ntohs(readw(rbuffer + BUFFER_LENGTH_OFST));
 		rbufdata = rbuffer + offsetof(struct rec_buf, data);
 	}
 
 	SET_PAGE(ti->asb_page);
-       	isa_writeb(0, ti->asb + offsetof(struct asb_rec, ret_code));
+	writeb(0, ti->asb + offsetof(struct asb_rec, ret_code));
 
-       	isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+	writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
 
 	ti->tr_stats.rx_bytes += skb->len;
-       	ti->tr_stats.rx_packets++;
+	ti->tr_stats.rx_packets++;
 
-	skb->protocol = tr_type_trans(skb,dev);
- 	if (IPv4_p && (skb->protocol == ETH_P_IP)) { 
-		skb->csum      = chksum;
+	skb->protocol = tr_type_trans(skb, dev);
+	if (IPv4_p) {
+		skb->csum = chksum;
 		skb->ip_summed = 1;
 	}
 	netif_rx(skb);
 	dev->last_rx = jiffies;
+}				/*tr_rx */
+
+/*****************************************************************************/
+
+void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
+{
+	tmr->expires = jiffies + TR_RETRY_INTERVAL;
+	tmr->data = (unsigned long) dev;
+	tmr->function = tok_rerun;
+	init_timer(tmr);
+	add_timer(tmr);
 }
 
-static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
+/*****************************************************************************/
+
+void tok_rerun(unsigned long dev_addr){
+
+	struct net_device *dev = (struct net_device *)dev_addr;
+	struct tok_info *ti = (struct tok_info *) dev->priv;
+
+	if ( ti->open_action == RESTART){
+		ti->do_tok_int = FIRST_INT;
+		outb(0, dev->base_addr + ADAPTRESETREL);
+#ifdef ENABLE_PAGING
+		if (ti->page_mask)
+			writeb(SRPR_ENABLE_PAGING,
+				ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
+#endif
+
+		writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	} else
+		tok_open_adapter(dev_addr);
+}
+
+/*****************************************************************************/
+
+void ibmtr_readlog(struct net_device *dev)
 {
 	struct tok_info *ti;
-	unsigned long flags;
-	ti=(struct tok_info *) dev->priv;
 
-	netif_stop_queue(dev);
-	
-	/* lock against other CPUs */
-	spin_lock_irqsave(&(ti->lock), flags);
+	ti = (struct tok_info *) dev->priv;
 
-	/* Save skb; we'll need it when the adapter asks for the data */
-	ti->current_skb=skb;
+	ti->readlog_pending = 0;
 	SET_PAGE(ti->srb_page);
-	isa_writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command));
-	isa_writew(ti->exsap_station_id, ti->srb
-	       +offsetof(struct srb_xmit, station_id));
-	isa_writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD));
-	spin_unlock_irqrestore(&(ti->lock), flags);
-	dev->trans_start=jiffies;
-	return 0;
-}
+	writeb(DIR_READ_LOG, ti->srb);
+	writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
+	writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
 
-void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) {
-	tmr->expires  = jiffies + TR_RETRY_INTERVAL;
-	tmr->data     = (unsigned long) dev;
-	tmr->function = tok_open_adapter;
-	init_timer(tmr);
-	add_timer(tmr);
-}
+	netif_stop_queue(dev);
 
-void ibmtr_readlog(struct net_device *dev) {
-	 struct tok_info *ti;
-	 ti=(struct tok_info *) dev->priv;
-
-	 ti->readlog_pending = 0;
-	 SET_PAGE(ti->srb_page);
-	 isa_writeb(DIR_READ_LOG, ti->srb);
-	 isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
-	 isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
-	 
-	 netif_stop_queue(dev);
 }
 
+/*****************************************************************************/
+
 /* tok_get_stats():  Basically a scaffold routine which will return
    the address of the tr_statistics structure associated with
    this device -- the tr.... structure is an ethnet look-alike
    so at least for this iteration may suffice.   */
 
-static struct net_device_stats * tok_get_stats(struct net_device *dev) {
+static struct net_device_stats *tok_get_stats(struct net_device *dev)
+{
 
 	struct tok_info *toki;
-	toki=(struct tok_info *) dev->priv;
+	toki = (struct tok_info *) dev->priv;
 	return (struct net_device_stats *) &toki->tr_stats;
 }
 
-int ibmtr_change_mtu(struct net_device *dev, int mtu) {
+/*****************************************************************************/
+
+int ibmtr_change_mtu(struct net_device *dev, int mtu)
+{
 	struct tok_info *ti = (struct tok_info *) dev->priv;
-	
+
 	if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
 		return -EINVAL;
 	if (ti->ring_speed == 4 && mtu > ti->maxmtu4)
@@ -1860,12 +1894,12 @@
 	return 0;
 }
 
-#ifndef PCMCIA
+/*****************************************************************************/
 #ifdef MODULE
 
 /* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
-static struct net_device* dev_ibmtr[IBMTR_MAX_ADAPTERS];
-static int io[IBMTR_MAX_ADAPTERS] = {0xa20,0xa24};
+static struct net_device *dev_ibmtr[IBMTR_MAX_ADAPTERS];
+static int io[IBMTR_MAX_ADAPTERS] = { 0xa20, 0xa24 };
 static int irq[IBMTR_MAX_ADAPTERS];
 static int mem[IBMTR_MAX_ADAPTERS];
 
@@ -1875,50 +1909,61 @@
 
 int init_module(void)
 {
-        int i;
-        for (i = 0; io[i] && (i<IBMTR_MAX_ADAPTERS); i++) {
-	        irq[i] = 0;
+	int i;
+	int count=0;
+
+	find_turbo_adapters(io);
+	for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) {
+		irq[i] = 0;
 		mem[i] = 0;
 		dev_ibmtr[i] = NULL;
-                dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0);
-                if (dev_ibmtr[i] == NULL) {
-			if (i == 0)
-                        	return -ENOMEM;
-			break;
+		dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0);
+		if (dev_ibmtr[i] == NULL) { 
+			if (i==0)
+				return -ENOMEM;
+			break ; 
 		}
-
-	        dev_ibmtr[i]->base_addr = io[i];
-	        dev_ibmtr[i]->irq       = irq[i];
+		dev_ibmtr[i]->base_addr = io[i];
+		dev_ibmtr[i]->irq = irq[i];
 		dev_ibmtr[i]->mem_start = mem[i];
-		dev_ibmtr[i]->init      = &ibmtr_probe;
-
-	        if (register_trdev(dev_ibmtr[i]) != 0) {
+		dev_ibmtr[i]->init = &ibmtr_probe;
+		if (register_trdev(dev_ibmtr[i]) != 0) {
 			kfree(dev_ibmtr[i]);
 			dev_ibmtr[i] = NULL;
-		        if (i == 0) {
-			        printk("ibmtr: register_trdev() returned non-zero.\n");
-		                return -EIO;
-			} else {
-			        return 0;
-			}
-	        }
+			continue;
+		}
+		count++;
 	}
-	return 0;
-}
+	if (count) return 0;
+	printk("ibmtr: register_trdev() returned non-zero.\n");
+	return -EIO;
+}				/*init_module */
 
 void cleanup_module(void)
 {
-        int i;
+	int i,j;
 
-        for (i = 0; i < IBMTR_MAX_ADAPTERS; i++)
-	        if (dev_ibmtr[i]) {
-			 unregister_trdev(dev_ibmtr[i]);
-			 free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
-			 release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
-			 kfree(dev_ibmtr[i]->priv);
-			 kfree(dev_ibmtr[i]);
-			 dev_ibmtr[i] = NULL;
+	for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){
+		if(!dev_ibmtr[i]) continue;
+		if (dev_ibmtr[i]->base_addr) {
+			outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET);
+			for(j=jiffies+TR_RST_TIME;
+				time_before_eq(jiffies,j);) ;
+                        outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL);
                 }
+		unregister_trdev(dev_ibmtr[i]);
+		free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
+		release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
+#ifndef PCMCIA
+		{ 
+		struct tok_info *ti = (struct tok_info *)dev_ibmtr[i]->priv ; 
+		iounmap((u32 *)ti->mmio) ; 
+		iounmap((u32 *)ti->sram_virt) ; 
+		}
+#endif		
+		kfree(dev_ibmtr[i]->priv);
+		kfree(dev_ibmtr[i]);
+		dev_ibmtr[i] = NULL;
+	}
 }
-#endif /* MODULE */
-#endif
+#endif				/* MODULE */
diff -u --recursive --new-file v2.4.6/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in
--- v2.4.6/linux/drivers/net/wan/Config.in	Thu Apr 12 12:11:39 2001
+++ linux/drivers/net/wan/Config.in	Wed Jul  4 11:50:39 2001
@@ -49,7 +49,7 @@
 
    dep_tristate '  Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
 
-   dep_tristate '  SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m
+   tristate '  SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP
 
    tristate '  Generic HDLC driver' CONFIG_HDLC
    if [ "$CONFIG_HDLC" != "n" ]; then
diff -u --recursive --new-file v2.4.6/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.4.6/linux/drivers/pci/pci.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/pci/pci.c	Wed Jul  4 09:41:34 2001
@@ -279,7 +279,7 @@
 	 * This doesn't affect PME_Status, disables PME_En, and
 	 * sets PowerState to 0.
 	 */
-	if (dev->current_state == 3)
+	if (dev->current_state >= 3)
 		pmcsr = 0;
 	else {
 		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
@@ -1175,6 +1175,9 @@
 	class >>= 8;
 
 	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+
+	/* "Unknown power state" */
+	dev->current_state = 4;
 
 	switch (dev->hdr_type) {		    /* header type */
 	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
diff -u --recursive --new-file v2.4.6/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.4.6/linux/drivers/pcmcia/yenta.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/pcmcia/yenta.c	Wed Jul  4 14:41:33 2001
@@ -795,6 +795,8 @@
 	{ PD(TI,1251B),	&ti_ops },
 	{ PD(TI,1410),	&ti_ops },
 	{ PD(TI,1420),	&ti_ops },
+	{ PD(TI,4410),	&ti_ops },
+	{ PD(TI,4451),	&ti_ops },
 
 	{ PD(RICOH,RL5C465), &ricoh_ops },
 	{ PD(RICOH,RL5C466), &ricoh_ops },
diff -u --recursive --new-file v2.4.6/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.4.6/linux/drivers/pnp/isapnp.c	Wed Apr 18 11:49:11 2001
+++ linux/drivers/pnp/isapnp.c	Wed Jul  4 14:41:33 2001
@@ -22,6 +22,9 @@
  *		Peter Denison <peterd@pnd-pc.demon.co.uk>
  *  2000-06-14	Added isapnp_probe_devs() and isapnp_activate_dev()
  *		Christoph Hellwig <hch@caldera.de>
+ *  2001-06-03  Added release_region calls to correspond with
+ *		request_region calls when a failure occurs.  Also
+ *		added KERN_* constants to printk() calls.
  */
 
 #include <linux/config.h>
@@ -407,7 +410,7 @@
 		*size = tag & 0x07;
 	}
 #if 0
-	printk("tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
+	printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
 #endif
 	if (type == 0)				/* wrong type */
 		return -1;
@@ -887,7 +890,7 @@
 				isapnp_skip_bytes(size);
 			return 1;
 		default:
-			printk("isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number);
+			printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number);
 		}
 	      __skip:
 	      	if (size > 0)
@@ -941,7 +944,7 @@
 				isapnp_skip_bytes(size);
 			return;
 		default:
-			printk("isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number);
+			printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number);
 		}
 	      __skip:
 	      	if (size > 0)
@@ -988,10 +991,10 @@
 		isapnp_peek(header, 9);
 		checksum = isapnp_checksum(header);
 #if 0
-		printk("vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+		printk(KERN_DEBUG "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
 			header[0], header[1], header[2], header[3],
 			header[4], header[5], header[6], header[7], header[8]);
-		printk("checksum = 0x%x\n", checksum);
+		printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
 #endif
 		/* Don't be strict on the checksum, here !
                    e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/
@@ -1011,7 +1014,7 @@
 		INIT_LIST_HEAD(&card->devices);
 		isapnp_parse_resource_map(card);
 		if (isapnp_checksum_value != 0x00)
-			printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
+			printk(KERN_ERR "isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
 		card->checksum = isapnp_checksum_value;
 
 		list_add_tail(&card->node, &isapnp_cards);
@@ -2181,19 +2184,22 @@
 
 	if (isapnp_disable) {
 		isapnp_detected = 0;
-		printk("isapnp: ISA Plug & Play support disabled\n");
+		printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
 		return 0;
 	}
 #ifdef ISAPNP_REGION_OK
 	pidxr_res=request_region(_PIDXR, 1, "isapnp index");
 	if(!pidxr_res) {
-		printk("isapnp: Index Register 0x%x already used\n", _PIDXR);
+		printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
 		return -EBUSY;
 	}
 #endif
 	pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write");
 	if(!pnpwrp_res) {
-		printk("isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
+		printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
+#ifdef ISAPNP_REGION_OK
+		release_region(_PIDXR, 1);
+#endif
 		return -EBUSY;
 	}
 	
@@ -2202,12 +2208,16 @@
 	 *	so let the user know where.
 	 */
 	 
-	printk("isapnp: Scanning for PnP cards...\n");
+	printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");
 	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
 		isapnp_rdp |= 3;
 		isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
 		if(!isapnp_rdp_res) {
-			printk("isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
+			printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
+#ifdef ISAPNP_REGION_OK
+			release_region(_PIDXR, 1);
+#endif
+			release_region(isapnp_rdp, 1);
 			return -EBUSY;
 		}
 		isapnp_set_rdp();
@@ -2219,7 +2229,7 @@
 		    (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
 			isapnp_free_all_resources();
 			isapnp_detected = 0;
-			printk("isapnp: No Plug & Play device found\n");
+			printk(KERN_INFO "isapnp: No Plug & Play device found\n");
 			return 0;
 		}
 		isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
@@ -2231,19 +2241,19 @@
 		cards++;
 		if (isapnp_verbose) {
 			struct list_head *devlist;
-			printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
+			printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
 			if (isapnp_verbose < 2)
 				continue;
 			for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) {
 				struct pci_dev *dev = pci_dev_b(devlist);
-				printk("isapnp:   Device '%s'\n", dev->name[0]?card->name:"Unknown");
+				printk(KERN_INFO "isapnp:   Device '%s'\n", dev->name[0]?card->name:"Unknown");
 			}
 		}
 	}
 	if (cards) {
-		printk("isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":"");
+		printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":"");
 	} else {
-		printk("isapnp: No Plug & Play card found\n");
+		printk(KERN_INFO "isapnp: No Plug & Play card found\n");
 	}
 #ifdef CONFIG_PROC_FS
 	isapnp_proc_init();
diff -u --recursive --new-file v2.4.6/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c
--- v2.4.6/linux/drivers/s390/s390io.c	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/s390io.c	Wed Jul  4 11:50:39 2001
@@ -2157,6 +2157,7 @@
 	 * Get interrupt info from lowcore
 	 */
 	volatile tpi_info_t *tpi_info = (tpi_info_t*)(__LC_SUBCHANNEL_ID);
+	int cpu = smp_processor_id();
 
 	/*
 	 * take fast exit if CPU is in sync. I/O state
@@ -2182,7 +2183,9 @@
 		if ( tpi_info->adapter_IO == 1 &&
 		     tpi_info->int_type == IO_INTERRUPT_TYPE )
 		{
+			irq_enter(cpu, -1);
 			do_adapter_IO( tpi_info->intparm );
+			irq_exit(cpu, -1);
 		} 
 		else 
 		{
@@ -2200,9 +2203,11 @@
 				return;	/* this keeps the device boxed ... */
 			}
 	
+			irq_enter(cpu, irq);
 			s390irq_spin_lock( irq );
 			s390_process_IRQ( irq );
 			s390irq_spin_unlock( irq );
+			irq_exit(cpu, irq);
 		}
 
 #ifdef CONFIG_FAST_IRQ
@@ -3166,8 +3171,11 @@
 
 		} /* endif */
 
-		if ( rc )	// can only happen if stsch/msch fails
+		if ( rc )	/* can only happen if stsch/msch fails */
+		{
 			sync_isc_cnt = 0;
+			atomic_set( &sync_isc, -1);
+		}
 	}
 	else
 	{
@@ -4276,12 +4284,7 @@
 		{
 			ret = enable_cpu_sync_isc( irq );
 
-			if ( ret )
-			{
-				free_irq( irq, &devstat );
-				return; // fixme ! fast exit ... grr
-			}
-			else
+			if ( !ret )
 			{
 				ioinfo[irq]->ui.flags.unknown = 0;
 
@@ -5270,24 +5273,28 @@
 
 					} /* endif */
 				}
-				else if ( ret )
+				else if ( ret == -EIO )
 				{
-
 #ifdef CONFIG_DEBUG_IO
-						printk( "PathVerification(%04X) "
-						        "- Device %04X doesn't "
-						        " support path grouping\n",
-						        irq,
-						        ioinfo[irq]->schib.pmcw.dev);
-
+					printk("PathVerification(%04X) - I/O error "
+					       "on device %04X\n", irq,
+					       ioinfo[irq]->schib.pmcw.dev);
 #endif
-
 					ioinfo[irq]->ui.flags.pgid_supp = 0;
-
+		    
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk( "PathVerification(%04X) "
+						"- Unexpected error on device %04X\n",
+						irq,
+						ioinfo[irq]->schib.pmcw.dev);
+#endif
+					ioinfo[irq]->ui.flags.pgid_supp = 0;
+					
 				} /* endif */
 
 			} /* endif */
-
+			
 		} /* endfor */
 
 	} /* endif */
@@ -5442,9 +5449,9 @@
 
 						} /* endif */
 					}
-#ifdef CONFIG_DEBUG_IO
 					else
 					{
+#ifdef CONFIG_DEBUG_IO
 						printk( "SPID - device %04X,"
 						        " unit check,"
 						        " retry %d, cnt %02d,"
@@ -5462,8 +5469,10 @@
 						        pdevstat->ii.sense.data[6],
 						        pdevstat->ii.sense.data[7]);
 
-					} /* endif */
 #endif
+						retry--;
+
+					} /* endif */
 				}
 				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
 				{
@@ -5474,6 +5483,7 @@
 					        irq);
 
 					retry = 0;
+					irq_ret = -EIO;
 
 				} /* endif */
 			}
@@ -5489,6 +5499,12 @@
 
 		} while ( retry > 0 );
 
+		if ( retry == 0 )
+		{
+			irq_ret = -EIO;
+
+		} /* endif */		
+
 		if ( init_IRQ_complete )
 		{
 			kfree( spid_ccw );
@@ -5693,6 +5709,12 @@
 
 		} while ( retry > 0 );
 
+		if ( retry == 0 )
+		{
+			irq_ret = -EIO;
+
+		} /* endif */
+
 		if ( init_IRQ_complete )
 		{
 			kfree( snid_ccw );
@@ -5936,7 +5958,10 @@
 		}
 	}
 
-	do_reipl( 0x10000 | sch );
+	if (MACHINE_IS_VM)
+		cpcmd("IPL", NULL, 0);
+	else
+		do_reipl( 0x10000 | sch );
 }
 
 /* Display info on subchannels in /proc/subchannels. *
diff -u --recursive --new-file v2.4.6/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.4.6/linux/drivers/sbus/char/aurora.c	Wed May 16 10:31:27 2001
+++ linux/drivers/sbus/char/aurora.c	Fri Jul  6 16:46:22 2001
@@ -1,4 +1,4 @@
-/*	$Id: aurora.c,v 1.13 2001/05/10 01:45:38 davem Exp $
+/*	$Id: aurora.c,v 1.14 2001/06/29 23:07:37 davem Exp $
  *	linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
  *
  *	Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
@@ -1851,7 +1851,6 @@
 static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd,
 				 unsigned int *value)
 {
-	int error;
 	unsigned int arg;
 	unsigned long flags;
 	struct Aurora_board *bp = port_Board(port);
@@ -1860,9 +1859,8 @@
 #ifdef AURORA_DEBUG
 	printk("aurora_set_modem_info: start\n");
 #endif
-	error = get_user(arg, value);
-	if (error) 
-		return error;
+	if (get_user(arg, value))
+		return -EFAULT;
 	chip = AURORA_CD180(port_No(port));
 	switch (cmd) {
 	 case TIOCMBIS: 
@@ -1940,16 +1938,12 @@
 	struct Aurora_board *bp = port_Board(port);
 	int change_speed;
 	unsigned long flags;
-	int error;
 
 #ifdef AURORA_DEBUG
 	printk("aurora_set_serial_info: start\n");
 #endif
-	error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
-	if (error)
-		return error;
-	copy_from_user(&tmp, newinfo, sizeof(tmp));
-	
+	if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+		return -EFAULT;
 #if 0	
 	if ((tmp.irq != bp->irq) ||
 	    (tmp.port != bp->base) ||
@@ -2025,7 +2019,6 @@
 		    
 {
 	struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-	int error;
 	int retval;
 
 #ifdef AURORA_DEBUG
@@ -2051,25 +2044,19 @@
 		aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
 		return 0;
 	case TIOCGSOFTCAR:
-		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-		if (error)
-			return error;
-		put_user(C_CLOCAL(tty) ? 1 : 0,
-			 (unsigned long *) arg);
-		return 0;
+		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
 	case TIOCSSOFTCAR:
-		retval = get_user(arg,(unsigned long *) arg);
-		if (retval)
-			return retval;
+		if (get_user(arg,(unsigned long *)arg))
+			return -EFAULT;
 		tty->termios->c_cflag =
 			((tty->termios->c_cflag & ~CLOCAL) |
 			 (arg ? CLOCAL : 0));
 		return 0;
 	case TIOCMGET:
-		error = verify_area(VERIFY_WRITE, (void *) arg,
+		retval = verify_area(VERIFY_WRITE, (void *) arg,
 				    sizeof(unsigned int));
-		if (error)
-			return error;
+		if (retval)
+			return retval;
 		return aurora_get_modem_info(port, (unsigned int *) arg);
 	case TIOCMBIS:
 	case TIOCMBIC:
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.4.6/linux/drivers/scsi/BusLogic.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/BusLogic.c	Thu Jul  5 11:28:16 2001
@@ -770,15 +770,19 @@
       BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
       unsigned char Bus = PCI_Device->bus->number;
       unsigned char Device = PCI_Device->devfn >> 3;
-      unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0);
-      unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1);
-      BusLogic_IO_Address_T IO_Address = BaseAddress0;
-      BusLogic_PCI_Address_T PCI_Address = BaseAddress1;
+      unsigned int IRQ_Channel;
+      unsigned long BaseAddress0;
+      unsigned long BaseAddress1;
+      BusLogic_IO_Address_T IO_Address;
+      BusLogic_PCI_Address_T PCI_Address;
 
       if (pci_enable_device(PCI_Device))
       	continue;
       
+      IRQ_Channel = PCI_Device->irq;
+      IO_Address  = BaseAddress0 = pci_resource_start(PCI_Device, 0);
+      PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1);
+
       if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM)
 	{
 	  BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
@@ -2547,7 +2551,7 @@
 	  int SynchronousTransferRate = 0;
 	  if (BusLogic_FlashPointHostAdapterP(HostAdapter))
 	    {
-	      boolean WideTransfersActive;
+	      unsigned char WideTransfersActive;
 	      FlashPoint_InquireTargetInfo(
 		HostAdapter->CardHandle, TargetID,
 		&HostAdapter->SynchronousPeriod[TargetID],
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.4.6/linux/drivers/scsi/BusLogic.h	Mon Dec 11 13:18:58 2000
+++ linux/drivers/scsi/BusLogic.h	Thu Jul  5 11:28:17 2001
@@ -78,6 +78,7 @@
     reset:          BusLogic_ResetCommand,	  /* Reset Command Function */ \
     bios_param:     BusLogic_BIOSDiskParameters,  /* BIOS Disk Parameters   */ \
     unchecked_isa_dma: 1,			  /* Default Initial Value  */ \
+    max_sectors:    128,			  /* I/O queue len limit    */ \
     use_clustering: ENABLE_CLUSTERING }		  /* Enable Clustering	    */
 
 
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.4.6/linux/drivers/scsi/ChangeLog.ncr53c8xx	Tue Mar  6 19:34:25 2001
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Thu Jul  5 11:28:17 2001
@@ -1,3 +1,9 @@
+Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.3b
+	- Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM.
+	  Fix sent by Stig Telfer <stig@api-networks.com>.
+	- Define scsi_set_pci_device() as nil for kernel < 2.4.4.
+
 Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr)
 	* version ncr53c8xx-3.4.3
 	- Call pci_enable_device() as AC wants this to be done.
@@ -238,7 +244,7 @@
 	- Changes from Eddie Dost for Sparc and Alpha:
 	  ioremap/iounmap support for Sparc.
 	  pcivtophys changed to bus_dvma_to_phys.
-	- Add the 53c876 description to the chip table. This is only usefull 
+	- Add the 53c876 description to the chip table. This is only useful 
 	  for printing the right name of the controller.
 	- DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15).
 	- Add additionnal checking of INQUIRY data:
@@ -304,7 +310,7 @@
 Sat Jun 20 20:00 1998 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.0c
 	- Add a boot setup option that allows to set up device queue depths 
-	  at boot-up. This option is very usefull since Linux does not 
+	  at boot-up. This option is very useful since Linux does not 
 	  allow to change scsi device queue depth once the system has been 
 	  booted up.
 
@@ -333,7 +339,7 @@
 	  kernel version >= 2.1.105.
 	- Replace all printf(s) by printk(s). After all, the ncr53c8xx is 
 	  a driver for Linux.
-	- Perform auto-sense on COMMAND TERMINATED. Not sure it is usefull.
+	- Perform auto-sense on COMMAND TERMINATED. Not sure it is useful.
 	- Some other minor changes.
 
 Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr)
@@ -341,7 +347,7 @@
 	- Code cleanup and simplification:
 	  Remove kernel 1.2.X and 1.3.X support.
 	  Remove the _old_ target capabilities table.
-	  Remove the error recovery code that have'nt been really usefull.
+	  Remove the error recovery code that have'nt been really useful.
 	  Use a single alignment boundary (CACHE_LINE_SIZE) for data 
 	  structures.
 	- Several aggressive SCRIPTS optimizations and changes:
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx
--- v2.4.6/linux/drivers/scsi/ChangeLog.sym53c8xx	Tue Mar  6 19:34:25 2001
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Thu Jul  5 11:28:16 2001
@@ -1,3 +1,24 @@
+Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.3c
+	- Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM.
+	  Fix sent by Stig Telfer <stig@api-networks.com>.
+	- Backport from SYM-2 the work-around that allows to support 
+	  hardwares that fail PCI parity checking.
+	- Check that we received at least 8 bytes of INQUIRY response 
+	  for byte 7, that contains device capabilities, to be valid.
+	- Define scsi_set_pci_device() as nil for kernel < 2.4.4.
+	- + A couple of minor changes.
+	  
+Sat Apr 7 19:30 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.3b
+	- Fix an unaligned LOAD from scripts (was used as dummy read).
+	- In ncr_soft_reset(), only try to ABORT the current operation 
+	  for chips that support SRUN bit in ISTAT1 and if SCRIPTS are 
+	  currently running, as 896 and 1010 manuals suggest.
+	- In the CCB abort path, donnot assume that the CCB is currently 
+	  queued to SCRIPTS. This is not always true, notably after a 
+	  QUEUE FULL status or when using untagged commands.
+
 Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.7.3a
 	- Fix an issue in the ncr_int_udc() (unexpected disconnect)
@@ -338,7 +359,7 @@
 Tue Apr 15  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.3e
 	- Support for any number of LUNs (64) (SPI2-compliant).
-	  (Btw, this may only be ever usefull under linux-2.2 ;-))
+	  (Btw, this may only be ever useful under linux-2.2 ;-))
 
 Sun Apr 11  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.3d
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.4.6/linux/drivers/scsi/Config.in	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/Config.in	Thu Jul  5 11:28:16 2001
@@ -101,7 +101,7 @@
    fi
 fi
 if [ "$CONFIG_X86" = "y" ]; then
-   dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
+   dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI $CONFIG_PCI
 fi
 dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI $CONFIG_PCI
 dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI $CONFIG_PCI
@@ -196,6 +196,30 @@
 fi
 if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
    bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP
+fi
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI
+   fi
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
+   dep_tristate 'A2091/A590 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
+   dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
+   dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
+   dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
+   dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
+   dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
+   dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI
+      bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI
+      bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI
+      dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
+#      bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
+#      bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI
+   fi
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/FlashPoint.c linux/drivers/scsi/FlashPoint.c
--- v2.4.6/linux/drivers/scsi/FlashPoint.c	Mon Aug 17 01:01:01 1998
+++ linux/drivers/scsi/FlashPoint.c	Thu Jul  5 11:28:16 2001
@@ -629,7 +629,7 @@
 #if (FW_TYPE==_UCB_MGR_)  
    #define  HBA_AUTO_SENSE_FAIL        0x1B  
    #define  HBA_TQ_REJECTED            0x1C  
-   #define  HBA_UNSUPORTED_MSG         0x1D  
+   #define  HBA_UNSUPPORTED_MSG         0x1D  
    #define  HBA_HW_ERROR               0x20  
    #define  HBA_ATN_NOT_RESPONDED      0x21  
    #define  HBA_SCSI_RESET_BY_ADAPTER  0x22
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.4.6/linux/drivers/scsi/README.aic7xxx	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/README.aic7xxx	Thu Jul  5 11:28:17 2001
@@ -0,0 +1,477 @@
+			    AIC7xxx Driver for Linux
+
+Introduction
+----------------------------
+The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
+SCSI controllers and chipsets. Major portions of the driver and driver
+development are shared between both Linux and FreeBSD. Support for the
+AIC-7xxx chipsets have been in the default Linux kernel since approximately
+linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
+2.1.0 or later.
+
+  Supported cards/chipsets
+  ----------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-274x
+    AHA-274xT
+    AHA-274xW
+    AHA-284x
+    AHA-284xW
+    All PCI based cards using any of the chipsets listed under motherboard
+    chipsets.  In general, this means *all* of the Adaptec SCSI controllers
+    except the ones specifically excluded later on in this document.
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-777x
+    AIC-785x
+    AIC-786x
+    AIC-787x
+    AIC-788x
+    AIC-789x
+    AIC-3860
+
+    Bus Types
+    ----------------------------
+    W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
+        SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
+    U - Ultra SCSI, transfer rates up to 40MB/s.
+    U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
+    U3- Ultra 3 SCSI, transfer rates up to 160MB/s.
+    D - Differential SCSI.
+    T - Twin Channel SCSI. Up to 14 SCSI devices.
+
+    AHA-274x - EISA SCSI controller
+    AHA-284x - VLB SCSI controller
+    AHA-29xx - PCI SCSI controller
+    AHA-39xx - PCI controllers with multiple separate SCSI channels on-board.
+
+  Not Supported Devices
+  ------------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-2920 (Only the cards that use the Future Domain chipset are not
+              supported, any 2920 cards based on Adaptec AIC chipsets,
+	      such as the 2920C, are supported)
+    AAA-13x Raid Adapters
+    AAA-113x Raid Port Card
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-781x
+
+    Bus Types
+    ----------------------------
+    R - Raid Port busses are not supported.
+
+    The hardware RAID devices sold by Adaptec are *NOT* supported by this
+    driver (and will people please stop emailing me about them, they are
+    a totally separate beast from the bare SCSI controllers and this driver
+    can not be retrofitted in any sane manner to support the hardware RAID
+    features on those cards - Doug Ledford).
+    
+
+  People
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@redhat.com
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
+    
+    Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
+    author of the driver. John has since retired from the project. Thanks
+    again for all his work!
+    
+  Mailing list
+  ------------------------------
+    There is a mailing list available for users who want to track development
+    and converse with other users and developers. This list is for both
+    FreeBSD and Linux support of the AIC7xxx chipsets.
+
+    To subscribe to the AIC7xxx mailing list send mail to the list server,
+    with "subscribe AIC7xxx" in the body (no Subject: required):
+        To: majordomo@FreeBSD.ORG
+        ---
+        subscribe AIC7xxx
+
+    To unsubscribe from the list, send mail to the list server with:
+        To: majordomo@FreeBSD.ORG
+        ---
+        unsubscribe AIC7xxx
+
+    Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
+    
+  Boot Command line options
+  ------------------------------
+    "aic7xxx=no_reset" -  Eliminate the SCSI bus reset during startup.
+        Some SCSI devices need the initial reset that this option disables
+	in order to work.  If you have problems at bootup, please make sure
+	you aren't using this option.
+	
+    "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at
+        bootup by scanning from the highest numbered PCI device to the
+	lowest numbered PCI device, others do just the opposite and scan
+	from lowest to highest numbered PCI device.  There is no reliable
+	way to autodetect this ordering.  So, we default to the most common
+	order, which is lowest to highest.  Then, in case your motherboard
+	scans from highest to lowest, we have this option.  If your BIOS
+	finds the drives on controller A before controller B but the linux
+	kernel finds your drives on controller B before A, then you should
+	use this option.
+	
+    "aic7xxx=extended" - Force the driver to detect extended drive translation
+        on your controller.  This helps those people who have cards without
+        a SEEPROM make sure that linux and all other operating systems think
+        the same way about your hard drives.
+
+    "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
+        give the card more hardware SCB slots.  This allows the driver to use
+	that SCB RAM.  Without this option, the driver won't touch the SCB
+	RAM because it is known to cause problems on a few cards out there
+	(such as 3985 class cards).
+	
+    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+        to use the correct IRQ type for your card.  This only applies to EISA
+        based controllers.  On these controllers, 0 is for Edge triggered
+        interrupts, and 1 is for Level triggered interrupts.  If you aren't
+        sure or don't know which IRQ trigger type your EISA card uses, then
+        let the kernel autodetect the trigger type.
+	
+    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
+        simply specify aic7xxx=verbose, then the kernel will automatically
+	pick the default set of verbose messages for you to see.
+	Alternatively, you can specify the command as 
+	"aic7xxx=verbose:0xXXXX" where the X entries are replaced with
+	hexadecimal digits.  This option is a bit field type option.  For
+	a full listing of the available options, search for the 
+	#define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want
+	verbose messages, then it is recommended that you simply use the
+	aic7xxx=verbose variant of this command.
+	
+    "aic7xxx=pci_parity:x" - This option controls whether or not the driver
+        enables PCI parity error checking on the PCI bus.  By default, this
+        checking is disabled.  To enable the checks, simply specify pci_parity
+        with no value afterwords.  To reverse the parity from even to odd,
+        supply any number other than 0 or 255.  In short:
+          pci_parity     - Even parity checking (even is the normal PCI parity)
+          pci_parity:x   - Where x > 0, Odd parity checking
+          pci_parity:0   - No check (default)
+        NOTE: In order to get Even PCI parity checking, you must use the
+        version of the option that does not include the : and a number at
+        the end (unless you want to enter exactly 2^32 - 1 as the number).
+	
+    "aic7xxx=no_probe" - This option will disable the probing for any VLB
+        based 2842 controllers and any EISA based controllers.  This is
+	needed on certain newer motherboards where the normal EISA I/O ranges
+	have been claimed by other PCI devices.  Probing on those machines
+	will often result in the machine crashing or spontaneously rebooting
+	during startup.  Examples of machines that need this are the
+	Dell PowerEdge 6300 machines.
+
+    "aic7xxx=seltime:2" - This option controls how long the card waits
+        during a device selection sequence for the device to respond.
+	The original SCSI spec says that this "should be" 256ms.  This
+	is generally not required with modern devices.  However, some
+	very old SCSI I devices need the full 256ms.  Most modern devices
+	can run fine with only 64ms.  The default for this option is
+	64ms.  If you need to change this option, then use the following
+	table to set the proper value in the example above:
+	  0  -  256ms
+	  1  -  128ms
+	  2  -   64ms
+	  3  -   32ms
+	
+    "aic7xxx=panic_on_abort" - This option is for debugging and will cause
+        the driver to panic the linux kernel and freeze the system the first
+	time the drivers abort or reset routines are called.  This is most
+	helpful when some problem causes infinite reset loops that scroll too
+	fast to see.  By using this option, you can write down what the errors
+	actually are and send that information to me so it can be fixed.
+	
+    "aic7xxx=dump_card" - This option will print out the *entire* set of
+        configuration registers on the card during the init sequence.  This
+	is a debugging aid used to see exactly what state the card is in
+	when we finally finish our initialization routines.  If you don't
+	have documentation on the chipsets, this will do you absolutely
+	no good unless you are simply trying to write all the information
+	down in order to send it to me.
+	
+    "aic7xxx=dump_sequencer" - This is the same as the above options except
+        that instead of dumping the register contents on the card, this
+	option dumps the contents of the sequencer program RAM.  This gives
+	the ability to verify that the instructions downloaded to the
+	card's sequencer are indeed what they are suppossed to be.  Again,
+	unless you have documentation to tell you how to interpret these
+	numbers, then it is totally useless.
+	
+    "aic7xxx=override_term:0xffffffff" - This option is used to force the
+    	termination on your SCSI controllers to a particular setting.  This
+	is a bit mask variable that applies for up to 8 aic7xxx SCSI channels.
+	Each channel gets 4 bits, divided as follows:
+	bit   3   2   1   0
+	      |   |   |   Enable/Disable Single Ended Low Byte Termination
+	      |   |   En/Disable Single Ended High Byte Termination
+	      |   En/Disable Low Byte LVD Termination
+	      En/Disable High Byte LVD Termination
+
+	The upper 2 bits that deal with LVD termination only apply to Ultra2
+	controllers.  Futhermore, due to the current Ultra2 controller
+	designs, these bits are tied together such that setting either bit
+	enables both low and high byte LVD termination.  It is not possible
+	to only set high or low byte LVD termination in this manner.  This is
+	an artifact of the BIOS definition on Ultra2 controllers.  For other
+	controllers, the only important bits are the two lowest bits.  Setting
+	the higher bits on non-Ultra2 controllers has no effect.  A few
+	examples of how to use this option:
+
+	Enable low and high byte termination on a non-ultra2 controller that
+	is the first aic7xxx controller (the correct bits are 0011), 
+	aic7xxx=override_term:0x3
+
+	Enable all termination on the third aic7xxx controller, high byte
+	termination on the second aic7xxx controller, and low and high byte
+	SE termination on the first aic7xxx controller 
+	(bits are 1111 0010 0011), 
+	aic7xxx=override_term:0xf23
+	
+	No attempt has been made to make this option non-cryptic.  It really
+	shouldn't be used except in dire circumstances, and if that happens,
+	I'm probably going to be telling you what to set this to anyway :)
+
+    "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV
+        bit in the DEVCONFIG PCI register.  Currently, this is one of the
+	very few registers that we have absolutely *no* way of detecting
+	what the variable should be.  It depends entirely on how the chipset
+	and external terminators were coupled by the card/motherboard maker.
+	Further, a chip reset (at power up) always sets this bit to 0.  If
+	there is no BIOS to run on the chipset/card (such as with a 2910C
+	or a motherboard controller with the BIOS totally disabled) then
+	the variable may not get set properly.  Of course, if the proper
+	setting was 0, then that's what it would be after the reset, but if
+	the proper setting is actually 1.....you get the picture.  Now, since
+	we can't detect this at all, I've added this option to force the
+	setting.  If you have a BIOS on your controller then you should never
+	need to use this option.  However, if you are having lots of SCSI
+	reset problems and can't seem to get them knocked out, this may help.
+
+	Here's a test to know for certain if you need this option.  Make
+	a boot floppy that you can use to boot your computer up and that
+	will detect the aic7xxx controller.  Next, power down your computer.
+	While it's down, unplug all SCSI cables from your Adaptec SCSI
+	controller.  Boot the system back up to the Adaptec EZ-SCSI BIOS
+	and then make sure that termination is enabled on your adapter (if
+	you have an Adaptec BIOS of course).  Next, boot up the floppy you
+	made and wait for it to detect the aic7xxx controller.  If the kernel
+	finds the controller fine, says scsi : x hosts and then tries to
+	detect your devices like normal, up to the point where it fails to
+	mount your root file system and panics, then you're fine.  If, on
+	the other hand, the system goes into an infinite reset loop, then
+	you need to use this option and/or the previous option to force the
+	proper termination settings on your controller.   If this happens,
+	then you next need to figure out what your settings should be.
+
+	To find the correct settings, power your machine back down, connect
+	back up the SCSI cables, and boot back into your machine like normal.
+	However, boot with the aic7xxx=verbose:0x39 option.  Record the
+	initial DEVCONFIG values for each of your aic7xxx controllers as
+	they are listed, and also record what the machine is detecting as
+	the proper termination on your controllers.  NOTE: the order in
+	which the initial DEVCONFIG values are printed out is not gauranteed
+	to be the same order as the SCSI controllers are registered.  The
+	above option and this option both work on the order of the SCSI
+	controllers as they are registered, so make sure you match the right
+	DEVCONFIG values with the right controllers if you have more than
+	one aic7xxx controller.
+
+	Once you have the detected termination settings and the initial
+	DEVCONFIG values for each controller, then figure out what the
+	termination on each of the controllers *should* be.  Hopefully, that
+	part is correct, but it could possibly be wrong if there is
+	bogus cable detection logic on your controller or something similar.
+	If all the controllers have the correct termination settings, then
+	don't set the aic7xxx=override_term variable at all, leave it alone.
+	Next, on any controllers that go into an infinite reset loop when
+	you unplug all the SCSI cables, get the starting DEVCONFIG value.
+	If the initial DEVCONFIG value is divisible by 2, then the correct
+	setting for that controller is 0.  If it's an odd number, then
+	the correct setting for that controller is 1.  For any other
+	controllers that didn't have an infinite reset problem, then reverse
+	the above options.  If DEVCONFIG was even, then the correct setting
+	is 1, if not then the correct setting is 0.
+
+	Now that you know what the correct setting was for each controller,
+	we need to encode that into the aic7xxx=stpwlev:0x... variable.
+	This variable is a bit field encoded variable.  Bit 0 is for the first
+	aic7xxx controller, bit 1 for the next, etc.  Put all these bits
+	together and you get a number.  For example, if the third aic7xxx
+	needed a 1, but the second and first both needed a 0, then the bits
+	would be 100 in binary.  This then translates to 0x04.  You would
+	therefore set aic7xxx=stpwlev:0x04.  This is fairly standard binary
+	to hexadecimal conversions here.  If you aren't up to speed on the
+	binary->hex conversion then send an email to the aic7xxx mailing
+	list and someone can help you out.
+
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
+        or enable Tagged Command Queueing (TCQ) on specific devices.  As of
+	driver version 5.1.11, TCQ is now either on or off by default
+	according to the setting you choose during the make config process.
+	In order to en/disable TCQ for certian devices at boot time, a user
+	may use this boot param.  The driver will then parse this message out
+        and en/disable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{,,,{,,,255}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 is disabled.  Notice that leading commas simply
+	  increment what the first number effects, and there are no need
+	  for trailing commas.  When you close out an adapter, or the
+	  entire entry, anything not explicitly set stays at the default
+	  value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma or
+    a period on the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the ? key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button
+    next to the option you have questions about.  The help information from
+    the Configure.help file will then get automatically displayed.
+
+  /proc support
+  ------------------------------
+    The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
+    directory. That directory contains a file for each SCSI controller in
+    the system. Each file presents the current configuration and transfer
+    statistics (enabled with #define in aic7xxx.c) for each controller.
+
+    Thanks to Michael Neuffer for his upper-level SCSI help, and
+    Matthew Jacob for statistics support.
+
+  Debugging the driver
+  ------------------------------
+    Should you have problems with this driver, and would like some help in
+    getting them solved, there are a couple debugging items built into
+    the driver to facilitate getting the needed information from the system.
+    In general, I need a complete description of the problem, with as many
+    logs as possible concerning what happens.  To help with this, there is
+    a command option aic7xxx=panic_on_abort.  This option, when set, forces
+    the driver to panic the kernel on the first SCSI abort issued by the
+    mid level SCSI code.  If your system is going to reset loops and you
+    can't read the screen, then this is what you need.  Not only will it
+    stop the system, but it also prints out a large amount of state
+    information in the process.  Second, if you specify the option
+    "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
+    information as it runs that you won't be able to see anything.
+    However, this can actually be very useful if your machine simply
+    locks up when trying to boot, since it will pin-point what was last
+    happening (in regards to the aic7xxx driver) immediately prior to
+    the lockup.  This is really only useful if your machine simply can
+    not boot up successfully.  If you can get your machine to run, then
+    this will produce far too much information.
+
+  FTP sites
+  ------------------------------
+    ftp://ftp.redhat.com/pub/aic/
+      - Out of date.  I used to keep stuff here, but too many people
+        complained about having a hard time getting into Red Hat's ftp
+	server.  So use the web site below instead.
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
+    ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
+      - European Linux mirror of Teleport site
+
+  Web sites
+  ------------------------------
+    http://people.redhat.com/dledford/
+      - My web site, also the primary aic7xxx site with several related
+        pages.
+
+Dean W. Gehnert
+deang@teleport.com
+
+$Revision: 3.0 $
+
+Modified by Doug Ledford 1998-2000
+
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.4.6/linux/drivers/scsi/README.ncr53c8xx	Mon Jun 19 17:59:41 2000
+++ linux/drivers/scsi/README.ncr53c8xx	Thu Jul  5 11:28:17 2001
@@ -508,7 +508,7 @@
     clearprof
 
     The profile counters are automatically cleared when the amount of
-    data transfered reaches 1000 GB in order to avoid overflow.
+    data transferred reaches 1000 GB in order to avoid overflow.
     The "clearprof" command allows you to clear these counters at any time.
 
 
@@ -1042,7 +1042,7 @@
 
 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 
+value at boot time. It is not that useful 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 
@@ -1350,7 +1350,7 @@
   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.
+             indicate the SCSI initiator that an error condition not reportable              using the SCSI protocol has occurred.
   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.
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
--- v2.4.6/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Fri May  4 15:16:28 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Thu Jul  5 11:28:16 2001
@@ -42,9 +42,13 @@
 static int	ahc_linux_pci_dev_probe(struct pci_dev *pdev,
 					const struct pci_device_id *ent);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/module.h>
+
 static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
 
-/* We do our own ID filtering.  So, grab all SCSI storage class devices. */
+/* We do our own ID filtering.  So we grab all Adaptec SCSI storage class
+ * devices here.
+ */
 static struct pci_device_id ahc_linux_pci_id_table[] = {
 	{
 		0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -56,6 +60,7 @@
 	},
 	{ 0 }
 };
+MODULE_DEVICE_TABLE(pci,ahc_linux_pci_id_table);
 
 struct pci_driver aic7xxx_pci_driver = {
 	name:		"aic7xxx",
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/README.aic7xxx linux/drivers/scsi/aic7xxx_old/README.aic7xxx
--- v2.4.6/linux/drivers/scsi/aic7xxx_old/README.aic7xxx	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx_old/README.aic7xxx	Thu Jul  5 11:28:16 2001
@@ -478,10 +478,10 @@
     information in the process.  Second, if you specify the option
     "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
     information as it runs that you won't be able to see anything.
-    However, this can actually be very usefull if your machine simply
+    However, this can actually be very useful if your machine simply
     locks up when trying to boot, since it will pin-point what was last
     happening (in regards to the aic7xxx driver) immediately prior to
-    the lockup.  This is really only usefull if your machine simply can
+    the lockup.  This is really only useful if your machine simply can
     not boot up successfully.  If you can get your machine to run, then
     this will produce far too much information.
 
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg linux/drivers/scsi/aic7xxx_old/aic7xxx.reg
--- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg	Fri Apr  6 10:51:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.reg	Thu Jul  5 11:28:17 2001
@@ -703,7 +703,12 @@
 						 * it that it can fill the
 						 * message buffer.
 						 */
-	mask	TRACEPOINT	0xb0|SEQINT
+	mask	SEQ_SG_FIXUP	0xb0|SEQINT	/* need help with fixing up
+						 * the sg array pointer after
+						 * a phasemis with no valid
+						 * sg elements in the shadow
+						 * pipeline.
+						 */
 	mask	TRACEPOINT2	0xc0|SEQINT
 	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
 						 * Target changed phase on us
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq linux/drivers/scsi/aic7xxx_old/aic7xxx.seq
--- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq	Fri Apr  6 10:51:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.seq	Thu Jul  5 11:28:17 2001
@@ -332,12 +332,15 @@
 	/* clear target specific flags */
 	clr	SEQ_FLAGS ret;
 
+
+data_phase_reinit:
 /*
  * If we re-enter the data phase after going through another phase, the
  * STCNT may have been cleared, so restore it from the residual field.
+ * On Ultra2, we have to put it into the HCNT field because we have to
+ * drop the data down into the shadow layer via the preload ability.
  */
-data_phase_reinit:
-	if ((p->features & AHC_ULTRA2) != 0) {
+ 	if ((p->features & AHC_ULTRA2) != 0) {
 		bmov	HADDR, SHADDR, 4;
 		bmov    HCNT, SCB_RESID_DCNT, 3;
 	}
@@ -349,27 +352,24 @@
 		mvi	SCB_RESID_DCNT	call bcopy_3;
 	}
 	jmp	data_phase_loop;
-
 p_data:
-	if ((p->features & AHC_ULTRA2) != 0) {
+ 	if ((p->features & AHC_ULTRA2) != 0) {
 		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
 	} else {
 		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
 	}
 	test	LASTPHASE, IOI jnz . + 2;
 	or	DMAPARAMS, DIRECTION;
-	call	assert;			/*
-					 * Ensure entering a data
-					 * phase is okay - seen identify, etc.
-					 */
+	call	assert;		/*
+				 * Ensure entering a data
+				 * phase is okay - seen identify, etc.
+				 */
 	if ((p->features & AHC_CMD_CHAN) != 0) {
 		mvi	CCSGADDR, CCSGADDR_MAX;
 	}
-	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
-
-	/* We have seen a data phase */
-	or	SEQ_FLAGS, DPHASE;
 
+	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+	or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
 	/*
 	 * Initialize the DMA address and counter from the SCB.
 	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
@@ -378,8 +378,10 @@
 	 */
 	if ((p->features & AHC_CMD_CHAN) != 0) {
 		bmov	HADDR, SCB_DATAPTR, 7;
-		bmov    STCNT, HCNT, 3;
 		bmov    SG_COUNT, SCB_SGCOUNT, 5;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		}
 	} else {
 		mvi	DINDEX, HADDR;
 		mvi	SCB_DATAPTR	call bcopy_7;
@@ -387,9 +389,8 @@
 		mvi	DINDEX, SG_COUNT;
 		mvi	SCB_SGCOUNT	call bcopy_5;
 	}
-
 data_phase_loop:
-/* Guard against overruns */
+	/* Guard against overruns */
 	test	SG_COUNT, 0xff jnz data_phase_inbounds;
 /*
  * Turn on 'Bit Bucket' mode, set the transfer count to
@@ -399,66 +400,62 @@
  */
 	or	SXFRCTL1,BITBUCKET;
 	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		if ((p->features & AHC_ULTRA2) != 0) {
-			bmov	HCNT, ALLONES, 3;
-		}
+	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov	HCNT, ALLONES, 3;
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
 		bmov	STCNT, ALLONES, 3;
-	} else {
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
 		mvi	STCNT[0], 0xFF;
 		mvi	STCNT[1], 0xFF;
 		mvi	STCNT[2], 0xFF;
 	}
+
 data_phase_inbounds:
 /* If we are the last SG block, tell the hardware. */
-	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
-	if ((p->features & AHC_ULTRA2) == 0) {
-		and	DMAPARAMS, ~WIDEODD;
+	if ((p->features & AHC_ULTRA2) != 0) {
+		shl	A, 2, SG_COUNT;
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		or	A, LAST_SEG;
 	} else {
-		mvi	SG_CACHEPTR, LAST_SEG;
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		and	DMAPARAMS, ~WIDEODD;
 	}
 data_phase_wideodd:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		mov	SINDEX, ALLONES;
-		mov	DFCNTRL, DMAPARAMS;
-		test	SSTAT0, SDONE jnz .;
-data_phase_dma_loop:
-		test	SSTAT0, SDONE jnz data_phase_dma_done;
-		test	SSTAT1,PHASEMIS	jz data_phase_dma_loop;	/* ie. underrun */
-data_phase_dma_phasemis:
-		test	SSTAT0,SDONE	jnz data_phase_dma_done;
-		clr	SINDEX;			/* Remember the phasemiss */
+	if ((p->features & AHC_ULTRA2) != 0) {	
+		mov	SG_CACHEPTR, A;
+		mov	DFCNTRL, DMAPARAMS; /* start the operation */
+		test	SXFRCTL1, BITBUCKET jnz data_phase_overrun;
+u2_preload_wait:
+		test	SSTAT1, PHASEMIS jnz u2_phasemis;
+		test	DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
 	} else {
 		mov	DMAPARAMS  call dma;
-	}
-
 data_phase_dma_done:
 /* Go tell the host about any overruns */
-	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+		test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
 
 /* Exit if we had an underrun.  dma clears SINDEX in this case. */
-	test	SINDEX,0xff	jz data_phase_finish;
-
+		test	SINDEX,0xff	jz data_phase_finish;
+	}
 /*
- * Advance the scatter-gather pointers if needed 
+ * Advance the scatter-gather pointers 
  */
 sg_advance:
-	dec	SG_COUNT;	/* one less segment to go */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		cmp	SG_COUNT, 0x01	je u2_data_phase_finish;
+	} else {
+		dec	SG_COUNT;
+		test	SG_COUNT, 0xff	jz data_phase_finish;
+	}
 
-	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
 	if ((p->features & AHC_CMD_CHAN) != 0) {
+
 		/*
 		 * Do we have any prefetch left???
 		 */
-		cmp	CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+		cmp	CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
 
 		/*
 		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
@@ -474,10 +471,12 @@
 		and	CCSGCTL, ~CCSGEN;
 		test	CCSGCTL, CCSGEN jnz .;
 		mvi	CCSGCTL, CCSGRESET;
-prefetched_segs_avail:
+prefetch_avail:
 		bmov 	HADDR, CCSGRAM, 8;
 		if ((p->features & AHC_ULTRA2) == 0) {
 			bmov    STCNT, HCNT, 3;
+		} else {
+			dec	SG_COUNT;
 		}
 	} else {
 		mvi	DINDEX, HADDR;
@@ -491,30 +490,63 @@
 
 		call	dma_finish;
 
-		/*
-		 * Copy data from FIFO into SCB data pointer and data count.
-		 * This assumes that the SG segments are of the form:
-		 * struct ahc_dma_seg {
-		 *	u_int32_t	addr;	four bytes, little-endian order
-		 *	u_int32_t	len;	four bytes, little endian order
-		 * };
-		 */
-		mvi	HADDR	call dfdat_in_7;
+/*
+ * Copy data from FIFO into SCB data pointer and data count.
+ * This assumes that the SG segments are of the form:
+ * struct ahc_dma_seg {
+ *	u_int32_t	addr;	four bytes, little-endian order
+ *	u_int32_t	len;	four bytes, little endian order
+ * };
+ */
+ 		mvi	DINDEX, HADDR;
+		call	dfdat_in_7;
 		call	set_stcnt_from_hcnt;
 	}
-
 /* Advance the SG pointer */
-	clr	A;			/* add sizeof(struct scatter) */
+	clr	A;		/* add sizeof(struct scatter) */
 	add	SG_NEXT[0],SG_SIZEOF;
 	adc	SG_NEXT[1],A;
 
-	test    SSTAT1, REQINIT jz .;
-	test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	if ((p->features & AHC_ULTRA2) != 0) {
+		jmp	data_phase_loop;
+	} else {
+		test    SSTAT1, REQINIT jz .;
+		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	}
+
 
-/* This drops the last SG segment down to the shadow layer for us */
+/*
+ * We've loaded all of our segments into the preload layer.  Now, we simply
+ * have to wait for it to finish or for us to get a phasemis.  And, since
+ * we'll get a phasemis if we do finish, all we really need to do is wait
+ * for a phasemis then check if we did actually complete all the segments.
+ */
 	if ((p->features & AHC_ULTRA2) != 0) {
-		mov	DFCNTRL, DMAPARAMS;
-		test	SSTAT0, SDONE	jnz .;
+u2_data_phase_finish:
+		test	SSTAT1, PHASEMIS jnz u2_phasemis;
+		test	SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
+		clr	SG_COUNT;
+		test	SSTAT1, REQINIT	jz .;
+		test	SSTAT1, PHASEMIS jz data_phase_loop;
+u2_phasemis:
+		call	ultra2_dmafinish;
+		test	SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish;
+		test	SSTAT2, SHVALID jnz u2_fixup_residual;
+		mvi	INTSTAT, SEQ_SG_FIXUP;
+		jmp	data_phase_finish;
+u2_fixup_residual:
+		shr	ARG_1, 2, SG_CACHEPTR;
+u2_phasemis_loop:
+		and	A, 0x3f, SG_COUNT;
+		cmp	ARG_1, A je data_phase_finish;
+/*
+ * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
+ */
+ 		clr	A;
+		add	SG_NEXT[0], -SG_SIZEOF;
+		adc	SG_NEXT[1], 0xff;
+		inc	SG_COUNT;
+		jmp	u2_phasemis_loop;
 	}
 
 data_phase_finish:
@@ -523,64 +555,83 @@
  * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
  * were transferred on the SCSI (as opposed to the host) bus.
  */
-	if ((p->features & AHC_ULTRA2) != 0) {
-		call	ultra2_dmafinish;
-	}
-	if ((p->features & AHC_ULTRA2) == 0) {
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov    SCB_RESID_DCNT, STCNT, 3;
-			mov	SCB_RESID_SGCNT, SG_COUNT;
-		} else {
-			mov	SCB_RESID_DCNT[0],STCNT[0];
-			mov	SCB_RESID_DCNT[1],STCNT[1];
-			mov	SCB_RESID_DCNT[2],STCNT[2];
-			mov	SCB_RESID_SGCNT, SG_COUNT;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_RESID_DCNT, STCNT, 3;
+		mov	SCB_RESID_SGCNT, SG_COUNT;
+		if ((p->features & AHC_ULTRA2) != 0) {
+			or	SXFRCTL0, CLRSTCNT|CLRCHN;
 		}
+	} else {
+		mov	SCB_RESID_DCNT[0],STCNT[0];
+		mov	SCB_RESID_DCNT[1],STCNT[1];
+		mov	SCB_RESID_DCNT[2],STCNT[2];
+		mov	SCB_RESID_SGCNT, SG_COUNT;
 	}
 
 	jmp	ITloop;
 
 data_phase_overrun:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		call	ultra2_dmafinish;
-	}
 /*
  * Turn off BITBUCKET mode and notify the host
  */
+	if ((p->features & AHC_ULTRA2) != 0) {
+/*
+ * Wait for the target to quit transferring data on the SCSI bus
+ */
+ 		test	SSTAT1, PHASEMIS jz .;
+		call	ultra2_dmafinish;
+	}
 	and	SXFRCTL1, ~BITBUCKET;
 	mvi	INTSTAT,DATA_OVERRUN;
 	jmp	ITloop;
 
-ultra2_dmafinish:
+
+
+
+/*
+ * Actually turn off the DMA hardware, save our current position into the
+ * proper residual variables, wait for the next REQ signal, then jump to
+ * the ITloop.  Jumping to the ITloop ensures that if we happen to get
+ * brought into the data phase again (or are still in it after our last
+ * segment) that we will properly signal an overrun to the kernel.
+ */
 	if ((p->features & AHC_ULTRA2) != 0) {
+ultra2_dmafinish:
 		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
 		and	DFCNTRL, ~SCSIEN;
 		test	DFCNTRL, SCSIEN jnz .;
+		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+			or	DFCNTRL, FIFOFLUSH;
+		}
 ultra2_dmafifoflush:
-		or	DFCNTRL, FIFOFLUSH;
-		test	DFSTATUS, FIFOEMP jz . - 1;
-		/*
-		 * hardware bug alert!  This needless set of jumps is to
-		 * protect against a FIFOEMP status bit glitch in the
-		 * silicon.
-		 */
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+			/*
+			 * hardware bug alert!  This needless set of jumps
+			 * works around a glitch in the silicon.  When the
+			 * PCI DMA fifo goes empty, but there is still SCSI
+			 * data to be flushed into the PCI DMA fifo (and from
+			 * there on into main memory), the FIFOEMP bit will
+			 * come on between the time when the PCI DMA buffer
+			 * went empty and the next bit of data is copied from
+			 * the SCSI fifo into the PCI fifo.  It should only
+			 * come on when both FIFOs (meaning the entire FIFO
+			 * chain) are emtpy.  Since it can take up to 4 cycles
+			 * for new data to be copied from the SCSI fifo into
+			 * the PCI fifo, testing for FIFOEMP status for 4
+			 * extra times gives the needed time for any
+			 * remaining SCSI fifo data to be put in the PCI fifo
+			 * before we declare it *truly* empty.
+			 */
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		}
 		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
 		test	DFSTATUS, MREQPEND	jnz .;
 ultra2_dmahalt:
-		test	SCSIOFFSET, 0x7f	jnz ultra2_shutdown;
-ultra2_await_nreq:
-		test	SCSISIGI, REQI	jz ultra2_shutdown;
-		test	SSTAT1, (PHASEMIS|REQINIT)	jz ultra2_await_nreq;
-ultra2_shutdown:
 		and     DFCNTRL, ~(HDMAEN|SCSIEN);
 		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
-		bmov	SCB_RESID_DCNT, STCNT, 3;
-		mov	SCB_RESID_SGCNT, SG_COUNT;
-		or	SXFRCTL0, CLRSTCNT|CLRCHN;
 		ret;
 	}
 
@@ -1021,6 +1072,7 @@
 inb_last:
 	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
 
+	
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -1080,7 +1132,9 @@
 	 * to drain the data fifo until there is space for the input
 	 * latch to drain and HDMAEN de-asserts.
 	 */
-	mov	NONE, DFDAT;
+	if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+		mov	NONE, DFDAT;
+	}
 	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
 }
 return:
@@ -1306,20 +1360,30 @@
 		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
 		jmp	dma_scb_finish;
 dma_scb_tohost:
-		if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		if ((p->features & AHC_ULTRA2) == 0) {
 			mvi	CCSCBCTL, CCSCBRESET;
 			bmov	CCSCBRAM, SCB_CONTROL, 32;
 			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
 			test	CCSCBCTL, CCSCBDONE jz .;
-		} else {
-			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
-			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+		}
+		if ((p->features & AHC_ULTRA2) != 0) {
+			if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
+				mvi     CCSCBCTL, CCARREN|CCSCBRESET;
+				cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
+                        	mvi     CCHCNT, 32;
+				mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
+				cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+			} else {
+				mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+				cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+			}
 		}
 dma_scb_finish:
 		clr	CCSCBCTL;
 		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
 		ret;
-	} else {
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
 		mvi	DINDEX, HADDR;
 		mvi	HSCB_ADDR call set_32byte_addr;
 		mvi	HCNT[0], 32;
@@ -1342,17 +1406,81 @@
 		mov	DFDAT,SINDIR;
 		cmp	SINDEX, A jne copy_scb_tofifo_loop;
 		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
 dma_scb_fromhost:
-		call	dma_finish;
-		/* If we were putting the SCB, we are done */
-		test	DMAPARAMS, DIRECTION	jz	return;
-		mvi	SCB_CONTROL  call dfdat_in_7;
-		call	dfdat_in_7_continued;
-		call	dfdat_in_7_continued;
-		jmp	dfdat_in_7_continued;
+		mvi	DINDEX, SCB_CONTROL;
+		if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+			/*
+			 * Set the A to -24.  It it hits 0, then we let
+			 * our code fall through to dfdat_in_8 to complete
+			 * the last of the copy.
+			 *
+			 * Also, things happen 8 bytes at a time in this
+			 * case, so we may need to drain the fifo at most
+			 * 3 times to keep things flowing
+			 */
+			mvi	A, -24;
+dma_scb_hang_fifo:
+			/* Wait for the first bit of data to hit the fifo */
+			test	DFSTATUS, FIFOEMP jnz .;
+dma_scb_hang_wait:
+			/* OK, now they've started to transfer into the fifo,
+			 * so wait for them to stop trying to transfer any
+			 * more data.
+			 */
+			test	DFSTATUS, MREQPEND jnz .;
+			/*
+			 * OK, they started, then they stopped, now see if they
+			 * managed to complete the job before stopping.  Try
+			 * it multiple times to give the chip a few cycles to
+			 * set the flag if it did complete.
+			 */
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			/*
+			 * Too bad, the chip didn't complete the DMA, but there
+			 * aren't any more memory requests pending, so that
+			 * means it stopped part way through and hung.  That's
+			 * our bug, so now we drain what data there is in the
+			 * fifo in order to get things going again.
+			 */
+dma_scb_hang_empty_fifo:
+			call	dfdat_in_8;
+			add	A, 8;
+			add	SINDEX, A, HCNT;
+			/*
+			 * If there are another 8 bytes of data waiting in the
+			 * fifo, then the carry bit will be set as a result
+			 * of the above add command (unless A is non-negative,
+			 * in which case the carry bit won't be set).
+			 */
+			jc	dma_scb_hang_empty_fifo;
+			/*
+			 * We've emptied the fifo now, but we wouldn't have got
+			 * here if the memory transfer hadn't stopped part way
+			 * through, so go back up to the beginning of the
+			 * loop and start over.  When it succeeds in getting
+			 * all the data down, HDONE will be set and we'll
+			 * jump to the code just below here.
+			 */
+			jmp	dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+			and	DFCNTRL, ~HDMAEN;
+			test	DFCNTRL, HDMAEN jnz .;
+			call	dfdat_in_8;
+			add	A, 8;
+			cmp	A, 8 jne . - 2;
+			ret;
+		} else {
+			call	dma_finish;
+			call	dfdat_in_8;
+			call	dfdat_in_8;
+			call	dfdat_in_8;
+		}
+dfdat_in_8:
+		mov	DINDIR,DFDAT;
 dfdat_in_7:
-		mov     DINDEX,SINDEX;
-dfdat_in_7_continued:
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
--- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Thu Jul  5 11:28:17 2001
@@ -162,7 +162,7 @@
   size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
   size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
 #else
   size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h
--- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h	Thu Jul  5 11:28:17 2001
@@ -188,8 +188,8 @@
 #define		BRDRW           	0x04
 #define		BRDRW_ULTRA2    	0x02
 #define		BRDCTL1         	0x02
-#define		BRDCTL0         	0x01
 #define		BRDSTB_ULTRA2   	0x01
+#define		BRDCTL0         	0x01
 
 #define	SEECTL          		0x1e
 #define		EXTARBACK       	0x80
@@ -397,7 +397,7 @@
 #define		DATA_OVERRUN    	0xe1
 #define		MSGIN_PHASEMIS  	0xd1
 #define		TRACEPOINT2     	0xc1
-#define		TRACEPOINT      	0xb1
+#define		SEQ_SG_FIXUP    	0xb1
 #define		AWAITING_MSG    	0xa1
 #define		RESIDUAL        	0x81
 #define		BAD_STATUS      	0x71
@@ -465,8 +465,6 @@
 #define		TARGCRCENDEN    	0x08
 #define		TARGCRCCNTEN    	0x04
 
-#define	QOUTCNT         		0x9e
-
 #define	SCSIPHASE       		0x9e
 #define		SP_STATUS       	0x20
 #define		SP_COMMAND      	0x10
@@ -475,6 +473,8 @@
 #define		SP_DATA_IN      	0x02
 #define		SP_DATA_OUT     	0x01
 
+#define	QOUTCNT         		0x9e
+
 #define	SFUNCT          		0x9f
 #define		ALT_MODE        	0x80
 
@@ -595,8 +595,8 @@
 #define		RD_DFTHRSH_63   	0x03
 #define		RD_DFTHRSH_50   	0x02
 #define		RD_DFTHRSH_25   	0x01
-#define		RD_DFTHRSH_MIN  	0x00
 #define		WR_DFTHRSH_MIN  	0x00
+#define		RD_DFTHRSH_MIN  	0x00
 
 #define	SG_CACHEPTR     		0xfc
 #define		SG_USER_DATA    	0xfc
@@ -604,18 +604,18 @@
 #define		LAST_SEG_DONE   	0x01
 
 
-#define	CMD_GROUP_CODE_SHIFT	0x05
-#define	BUS_8_BIT	0x00
-#define	QOUTFIFO_OFFSET	0x01
-#define	CCSGRAM_MAXSEGS	0x10
 #define	CMD_GROUP2_BYTE_DELTA	0xfa
 #define	MAX_OFFSET_8BIT	0x0f
 #define	BUS_16_BIT	0x01
 #define	QINFIFO_OFFSET	0x02
 #define	CMD_GROUP5_BYTE_DELTA	0x0b
+#define	CMD_GROUP_CODE_SHIFT	0x05
 #define	MAX_OFFSET_ULTRA2	0x7f
 #define	MAX_OFFSET_16BIT	0x08
+#define	BUS_8_BIT	0x00
+#define	QOUTFIFO_OFFSET	0x01
 #define	UNTAGGEDSCB_OFFSET	0x00
+#define	CCSGRAM_MAXSEGS	0x10
 #define	SCB_LIST_NULL	0xff
 #define	SG_SIZEOF	0x08
 #define	CMD_GROUP4_BYTE_DELTA	0x04
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c
--- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c	Thu Jul  5 11:28:17 2001
@@ -25,12 +25,12 @@
 	0x00, 0x4d, 0x10, 0x70,
 	0x01, 0x4e, 0x9c, 0x18,
 	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0x3e, 0x5c,
+	0x00, 0x6a, 0x86, 0x5c,
 	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0x54, 0x5b,
+	0x02, 0x6a, 0x70, 0x5b,
 	0xff, 0x52, 0x20, 0x09,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0xca, 0x5b,
+	0x00, 0x52, 0xe6, 0x5b,
 	0x03, 0xb0, 0x52, 0x31,
 	0xff, 0xb0, 0x52, 0x09,
 	0xff, 0xb1, 0x54, 0x09,
@@ -87,13 +87,13 @@
 	0x08, 0x6a, 0x66, 0x58,
 	0x80, 0x6a, 0x68, 0x00,
 	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0x9e, 0x5b,
+	0x00, 0x65, 0xba, 0x5b,
 	0xff, 0x3d, 0xc8, 0x08,
 	0xbf, 0x64, 0xe2, 0x78,
-	0x80, 0x64, 0xac, 0x71,
-	0xa0, 0x64, 0xdc, 0x71,
-	0xc0, 0x64, 0xd4, 0x71,
-	0xe0, 0x64, 0x1c, 0x72,
+	0x80, 0x64, 0xc8, 0x71,
+	0xa0, 0x64, 0xf8, 0x71,
+	0xc0, 0x64, 0xf0, 0x71,
+	0xe0, 0x64, 0x38, 0x72,
 	0x01, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
 	0xf7, 0x11, 0x22, 0x08,
@@ -113,24 +113,24 @@
 	0x03, 0xa9, 0x18, 0x31,
 	0x03, 0xa9, 0x10, 0x30,
 	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0xb4, 0x5b,
+	0xa9, 0x6a, 0xd0, 0x5b,
 	0x00, 0x65, 0x02, 0x41,
 	0xa8, 0x6a, 0x6a, 0x00,
 	0x79, 0x6a, 0x6a, 0x00,
 	0x40, 0x3d, 0xea, 0x68,
 	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x0e, 0x5b,
+	0x00, 0x65, 0x2a, 0x5b,
 	0x80, 0x6a, 0xd4, 0x01,
 	0x10, 0x36, 0xd6, 0x68,
 	0x10, 0x36, 0x6c, 0x00,
 	0x07, 0xac, 0x10, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
 	0x05, 0xa3, 0x70, 0x30,
+	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0xac, 0x5b,
-	0x00, 0x65, 0xa6, 0x5b,
+	0xac, 0x6a, 0xc8, 0x5b,
+	0x00, 0x65, 0xc2, 0x5b,
 	0x38, 0x6a, 0xcc, 0x00,
-	0xa3, 0x6a, 0xb0, 0x5b,
+	0xa3, 0x6a, 0xcc, 0x5b,
 	0xff, 0x38, 0x12, 0x69,
 	0x80, 0x02, 0x04, 0x00,
 	0xe7, 0x35, 0x6a, 0x08,
@@ -139,334 +139,348 @@
 	0xff, 0x6a, 0x10, 0x00,
 	0xff, 0x6a, 0x12, 0x00,
 	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0x18, 0x61,
+	0x22, 0x38, 0xc8, 0x28,
+	0x01, 0x38, 0x1c, 0x61,
+	0x02, 0x64, 0xc8, 0x00,
+	0x01, 0x38, 0x1c, 0x61,
 	0xbf, 0x35, 0x6a, 0x08,
-	0x02, 0x6a, 0xf8, 0x01,
-	0xff, 0x69, 0xca, 0x08,
+	0xff, 0x64, 0xf8, 0x09,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x1c, 0x69,
-	0x04, 0x0b, 0x28, 0x69,
-	0x10, 0x0c, 0x1e, 0x79,
-	0x04, 0x0b, 0x28, 0x69,
-	0xff, 0x6a, 0xca, 0x08,
-	0x00, 0x35, 0xee, 0x5a,
-	0x80, 0x02, 0x7c, 0x69,
-	0xff, 0x65, 0x6c, 0x79,
+	0x80, 0x02, 0xa4, 0x69,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x80, 0x94, 0x22, 0x79,
+	0x00, 0x35, 0x0a, 0x5b,
+	0x80, 0x02, 0xa4, 0x69,
+	0xff, 0x65, 0x94, 0x79,
+	0x01, 0x38, 0x70, 0x71,
 	0xff, 0x38, 0x70, 0x18,
-	0xff, 0x38, 0x6c, 0x79,
-	0x80, 0xea, 0x48, 0x61,
+	0xff, 0x38, 0x94, 0x79,
+	0x80, 0xea, 0x4a, 0x61,
 	0xef, 0x38, 0xc8, 0x18,
 	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0x3a, 0x49,
+	0x00, 0x65, 0x3c, 0x49,
 	0x33, 0x38, 0xc8, 0x28,
 	0xff, 0x64, 0xd0, 0x09,
 	0x04, 0x39, 0xc0, 0x31,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x40, 0x79,
+	0x80, 0xeb, 0x42, 0x79,
 	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0x44, 0x69,
+	0x08, 0xeb, 0x46, 0x69,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x08, 0xe9, 0x10, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
+	0xff, 0x38, 0x70, 0x18,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0xb2, 0x5b,
+	0x39, 0x6a, 0xce, 0x5b,
 	0x08, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0x88, 0x6a, 0x20, 0x5c,
-	0x00, 0x65, 0xa6, 0x5b,
+	0x00, 0x65, 0x78, 0x5c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x00, 0x65, 0x6a, 0x5c,
+	0x00, 0x65, 0xc2, 0x5b,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x08, 0x39, 0x72, 0x18,
 	0x00, 0x3a, 0x74, 0x20,
-	0x01, 0x0c, 0x64, 0x79,
+	0x00, 0x65, 0x02, 0x41,
+	0x01, 0x0c, 0x6c, 0x79,
 	0x10, 0x0c, 0x02, 0x79,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x6a, 0x69,
-	0x00, 0x65, 0x84, 0x59,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x01, 0xfc, 0x70, 0x79,
+	0xff, 0x6a, 0x70, 0x08,
+	0x01, 0x0c, 0x76, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x00, 0x65, 0xae, 0x59,
+	0x01, 0xfc, 0x94, 0x69,
+	0x40, 0x0d, 0x84, 0x69,
+	0xb1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x94, 0x41,
+	0x2e, 0xfc, 0xa2, 0x28,
+	0x3f, 0x38, 0xc8, 0x08,
+	0x00, 0x51, 0x94, 0x71,
+	0xff, 0x6a, 0xc8, 0x08,
+	0xf8, 0x39, 0x72, 0x18,
+	0xff, 0x3a, 0x74, 0x20,
+	0x01, 0x38, 0x70, 0x18,
+	0x00, 0x65, 0x86, 0x41,
 	0x03, 0x08, 0x52, 0x31,
 	0xff, 0x38, 0x50, 0x09,
+	0x12, 0x01, 0x02, 0x00,
 	0xff, 0x08, 0x52, 0x09,
 	0xff, 0x09, 0x54, 0x09,
 	0xff, 0x0a, 0x56, 0x09,
 	0xff, 0x38, 0x50, 0x09,
 	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x84, 0x59,
+	0x10, 0x0c, 0xa4, 0x79,
+	0x00, 0x65, 0xae, 0x59,
 	0x7f, 0x02, 0x04, 0x08,
 	0xe1, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
-	0x04, 0x93, 0x9a, 0x69,
+	0x04, 0x93, 0xc2, 0x69,
 	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x88, 0x69,
+	0x20, 0x93, 0xb2, 0x69,
 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x10, 0x94, 0x98, 0x69,
-	0x7f, 0x05, 0xa0, 0x69,
-	0x02, 0x03, 0xa0, 0x79,
-	0x11, 0x0c, 0x9c, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x10, 0x94, 0xc0, 0x69,
 	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xa2, 0x69,
-	0x03, 0x08, 0x52, 0x31,
-	0xff, 0x38, 0x50, 0x09,
-	0x12, 0x01, 0x02, 0x00,
+	0x28, 0x93, 0xc4, 0x69,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0x0e, 0x5b,
+	0x00, 0x65, 0x2a, 0x5b,
 	0x05, 0xb4, 0x10, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0xb0, 0x5b,
+	0xb4, 0x6a, 0xcc, 0x5b,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0xa6, 0x5b,
-	0x3d, 0x6a, 0xee, 0x5a,
+	0x00, 0x65, 0xc2, 0x5b,
+	0x3d, 0x6a, 0x0a, 0x5b,
 	0xac, 0x6a, 0x26, 0x01,
-	0x04, 0x0b, 0xc2, 0x69,
-	0x04, 0x0b, 0xc8, 0x69,
-	0x10, 0x0c, 0xc4, 0x79,
-	0x02, 0x03, 0xcc, 0x79,
-	0x11, 0x0c, 0xc8, 0x79,
+	0x04, 0x0b, 0xde, 0x69,
+	0x04, 0x0b, 0xe4, 0x69,
+	0x10, 0x0c, 0xe0, 0x79,
+	0x02, 0x03, 0xe8, 0x79,
+	0x11, 0x0c, 0xe4, 0x79,
 	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xce, 0x69,
+	0x28, 0x93, 0xea, 0x69,
 	0x12, 0x01, 0x02, 0x00,
 	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x0e, 0x5b,
+	0x00, 0x65, 0x2a, 0x5b,
 	0xff, 0x06, 0x44, 0x09,
 	0x00, 0x65, 0xaa, 0x40,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x00, 0x62,
+	0x80, 0x65, 0x1c, 0x62,
 	0x0f, 0xa1, 0xca, 0x08,
 	0x07, 0xa1, 0xca, 0x08,
 	0x40, 0xa0, 0xc8, 0x08,
 	0x00, 0x65, 0xca, 0x00,
 	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0xf0, 0x79,
+	0x80, 0xa0, 0x0c, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x02, 0x42,
-	0x20, 0xa0, 0x08, 0x7a,
+	0x00, 0x65, 0x1e, 0x42,
+	0x20, 0xa0, 0x24, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0x10, 0x62,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
 	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0x10, 0x62,
-	0x00, 0xb9, 0x08, 0x42,
-	0xff, 0x65, 0x08, 0x62,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
+	0x00, 0xb9, 0x24, 0x42,
+	0xff, 0x65, 0x24, 0x62,
 	0xa1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x10, 0x72,
+	0x10, 0x51, 0x2c, 0x72,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0xda, 0x71,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0xf6, 0x71,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x18, 0x62,
+	0x80, 0x34, 0x34, 0x62,
 	0x7f, 0xa0, 0x40, 0x09,
 	0x08, 0x6a, 0x68, 0x00,
 	0x00, 0x65, 0xaa, 0x40,
-	0x64, 0x6a, 0xe4, 0x5a,
-	0x80, 0x64, 0x8e, 0x6a,
-	0x04, 0x64, 0x70, 0x72,
-	0x02, 0x64, 0x76, 0x72,
-	0x00, 0x6a, 0x38, 0x72,
-	0x03, 0x64, 0x8a, 0x72,
-	0x01, 0x64, 0x6c, 0x72,
-	0x07, 0x64, 0xcc, 0x72,
-	0x08, 0x64, 0x34, 0x72,
-	0x23, 0x64, 0xd0, 0x72,
+	0x64, 0x6a, 0x00, 0x5b,
+	0x80, 0x64, 0xaa, 0x6a,
+	0x04, 0x64, 0x8c, 0x72,
+	0x02, 0x64, 0x92, 0x72,
+	0x00, 0x6a, 0x54, 0x72,
+	0x03, 0x64, 0xa6, 0x72,
+	0x01, 0x64, 0x88, 0x72,
+	0x07, 0x64, 0xe8, 0x72,
+	0x08, 0x64, 0x50, 0x72,
+	0x23, 0x64, 0xec, 0x72,
 	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0xd6, 0x5a,
+	0x07, 0x6a, 0xf2, 0x5a,
 	0xff, 0x06, 0xd4, 0x08,
 	0x00, 0x65, 0xaa, 0x40,
-	0xff, 0xa8, 0x3c, 0x6a,
-	0xff, 0xa2, 0x54, 0x7a,
+	0xff, 0xa8, 0x58, 0x6a,
+	0xff, 0xa2, 0x70, 0x7a,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0xa2, 0x54, 0x7a,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0xa2, 0x70, 0x7a,
 	0x71, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0x54, 0x62,
+	0x40, 0x51, 0x70, 0x62,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
+	0x00, 0xb9, 0xe6, 0x5b,
 	0xff, 0x3e, 0x74, 0x09,
 	0xff, 0x90, 0x7c, 0x08,
 	0x00, 0x65, 0x4e, 0x58,
 	0x00, 0x65, 0xbc, 0x40,
-	0x20, 0xa0, 0x5c, 0x6a,
+	0x20, 0xa0, 0x78, 0x6a,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0x74, 0x5b,
-	0xff, 0x6a, 0x8a, 0x5b,
+	0x00, 0x6a, 0x90, 0x5b,
+	0xff, 0x6a, 0xa6, 0x5b,
 	0xff, 0xf8, 0xc8, 0x08,
 	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0x74, 0x5b,
-	0x00, 0xb9, 0x8a, 0x5b,
+	0x01, 0x6a, 0x90, 0x5b,
+	0x00, 0xb9, 0xa6, 0x5b,
 	0x01, 0x4f, 0x9e, 0x18,
 	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x38, 0x5c,
+	0x00, 0x65, 0x80, 0x5c,
 	0x00, 0x65, 0xbc, 0x40,
 	0x41, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
 	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0x50, 0x5c,
+	0x00, 0x65, 0x98, 0x5c,
 	0x00, 0x65, 0xbc, 0x40,
-	0x10, 0x36, 0x34, 0x7a,
+	0x10, 0x36, 0x50, 0x7a,
 	0x05, 0x38, 0x46, 0x31,
 	0x04, 0x14, 0x58, 0x31,
 	0x03, 0xa9, 0x60, 0x31,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0x38, 0x6a, 0xb0, 0x5b,
+	0x38, 0x6a, 0xcc, 0x5b,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xb2, 0x5b,
-	0xa9, 0x6a, 0xb4, 0x5b,
-	0x00, 0x65, 0x34, 0x42,
+	0x14, 0x6a, 0xce, 0x5b,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x50, 0x42,
 	0xef, 0x36, 0x6c, 0x08,
-	0x00, 0x65, 0x34, 0x42,
+	0x00, 0x65, 0x50, 0x42,
 	0x0f, 0x64, 0xc8, 0x08,
 	0x07, 0x64, 0xc8, 0x08,
 	0x00, 0x37, 0x6e, 0x00,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0x44, 0x5b,
-	0xff, 0x51, 0xa0, 0x72,
-	0x20, 0x36, 0xaa, 0x7a,
-	0x00, 0x90, 0x32, 0x5b,
-	0x00, 0x65, 0xac, 0x42,
+	0x00, 0x65, 0x60, 0x5b,
+	0xff, 0x51, 0xbc, 0x72,
+	0x20, 0x36, 0xc6, 0x7a,
+	0x00, 0x90, 0x4e, 0x5b,
+	0x00, 0x65, 0xc8, 0x42,
 	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xe0, 0x3d, 0xc6, 0x62,
-	0x20, 0x12, 0xc6, 0x62,
-	0x51, 0x6a, 0xda, 0x5a,
-	0x00, 0x65, 0x2c, 0x5b,
+	0x00, 0x65, 0xba, 0x5b,
+	0xe0, 0x3d, 0xe2, 0x62,
+	0x20, 0x12, 0xe2, 0x62,
+	0x51, 0x6a, 0xf6, 0x5a,
+	0x00, 0x65, 0x48, 0x5b,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0xa1, 0xbe, 0x62,
-	0x04, 0xa0, 0xbe, 0x7a,
+	0x00, 0xa1, 0xda, 0x62,
+	0x04, 0xa0, 0xda, 0x7a,
 	0xfb, 0xa0, 0x40, 0x09,
 	0x80, 0x36, 0x6c, 0x00,
-	0x80, 0xa0, 0x34, 0x7a,
+	0x80, 0xa0, 0x50, 0x7a,
 	0x7f, 0xa0, 0x40, 0x09,
-	0xff, 0x6a, 0xd6, 0x5a,
-	0x00, 0x65, 0x34, 0x42,
-	0x04, 0xa0, 0xc4, 0x7a,
-	0x00, 0x65, 0x50, 0x5c,
-	0x00, 0x65, 0xc6, 0x42,
-	0x00, 0x65, 0x38, 0x5c,
+	0xff, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x04, 0xa0, 0xe0, 0x7a,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xe2, 0x42,
+	0x00, 0x65, 0x80, 0x5c,
 	0x31, 0x6a, 0x22, 0x01,
-	0x0c, 0x6a, 0xd6, 0x5a,
-	0x00, 0x65, 0x34, 0x42,
+	0x0c, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
 	0x61, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x34, 0x42,
-	0x51, 0x6a, 0xda, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x51, 0x6a, 0xf6, 0x5a,
 	0x51, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x34, 0x42,
+	0x00, 0x65, 0x50, 0x42,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x65, 0x68, 0x0c,
 	0xff, 0x06, 0xd4, 0x08,
-	0x01, 0x0c, 0xdc, 0x7a,
-	0x04, 0x0c, 0xde, 0x6a,
+	0x01, 0x0c, 0xf8, 0x7a,
+	0x04, 0x0c, 0xfa, 0x6a,
 	0xe0, 0x03, 0x7a, 0x08,
-	0xe0, 0x3d, 0xea, 0x62,
+	0xe0, 0x3d, 0x06, 0x63,
 	0xff, 0x65, 0xcc, 0x08,
 	0xff, 0x12, 0xda, 0x0c,
 	0xff, 0x06, 0xd4, 0x0c,
 	0xd1, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
 	0xff, 0x65, 0x26, 0x09,
-	0x01, 0x0b, 0xfe, 0x6a,
-	0x10, 0x0c, 0xf0, 0x7a,
-	0x04, 0x0b, 0xf8, 0x6a,
+	0x01, 0x0b, 0x1a, 0x6b,
+	0x10, 0x0c, 0x0c, 0x7b,
+	0x04, 0x0b, 0x14, 0x6b,
 	0xff, 0x6a, 0xca, 0x08,
-	0x04, 0x93, 0xfc, 0x6a,
-	0x01, 0x94, 0xfa, 0x7a,
-	0x10, 0x94, 0xfc, 0x6a,
-	0x80, 0x3d, 0x02, 0x73,
-	0x0f, 0x04, 0x06, 0x6b,
-	0x02, 0x03, 0x06, 0x7b,
-	0x11, 0x0c, 0x02, 0x7b,
+	0x04, 0x93, 0x18, 0x6b,
+	0x01, 0x94, 0x16, 0x7b,
+	0x10, 0x94, 0x18, 0x6b,
+	0x80, 0x3d, 0x1e, 0x73,
+	0x0f, 0x04, 0x22, 0x6b,
+	0x02, 0x03, 0x22, 0x7b,
+	0x11, 0x0c, 0x1e, 0x7b,
 	0xc7, 0x93, 0x26, 0x09,
 	0xff, 0x99, 0xd4, 0x08,
-	0x38, 0x93, 0x08, 0x6b,
+	0x38, 0x93, 0x24, 0x6b,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0x36, 0x0c, 0x6b,
+	0x80, 0x36, 0x28, 0x6b,
 	0x21, 0x6a, 0x22, 0x05,
 	0xff, 0x65, 0x20, 0x09,
-	0xff, 0x51, 0x1a, 0x63,
+	0xff, 0x51, 0x36, 0x63,
 	0xff, 0x37, 0xc8, 0x08,
-	0xa1, 0x6a, 0x26, 0x43,
+	0xa1, 0x6a, 0x42, 0x43,
 	0xff, 0x51, 0xc8, 0x08,
-	0xb9, 0x6a, 0x26, 0x43,
+	0xb9, 0x6a, 0x42, 0x43,
 	0xff, 0x90, 0xa4, 0x08,
-	0xff, 0xba, 0x2a, 0x73,
+	0xff, 0xba, 0x46, 0x73,
 	0xff, 0xba, 0x20, 0x09,
 	0xff, 0x65, 0xca, 0x18,
-	0x00, 0x6c, 0x1e, 0x63,
+	0x00, 0x6c, 0x3a, 0x63,
 	0xff, 0x90, 0xca, 0x0c,
 	0xff, 0x6a, 0xca, 0x04,
-	0x20, 0x36, 0x3e, 0x7b,
-	0x00, 0x90, 0x12, 0x5b,
-	0xff, 0x65, 0x3e, 0x73,
-	0xff, 0x52, 0x3c, 0x73,
+	0x20, 0x36, 0x5a, 0x7b,
+	0x00, 0x90, 0x2e, 0x5b,
+	0xff, 0x65, 0x5a, 0x73,
+	0xff, 0x52, 0x58, 0x73,
 	0xff, 0xba, 0xcc, 0x08,
 	0xff, 0x52, 0x20, 0x09,
 	0xff, 0x66, 0x74, 0x09,
 	0xff, 0x65, 0x20, 0x0d,
 	0xff, 0xba, 0x7e, 0x0c,
-	0x00, 0x6a, 0x3e, 0x5c,
+	0x00, 0x6a, 0x86, 0x5c,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x51, 0xca, 0x43,
-	0xff, 0x3f, 0x98, 0x73,
+	0x00, 0x51, 0xe6, 0x43,
+	0xff, 0x3f, 0xb4, 0x73,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3f, 0x12, 0x5b,
-	0xff, 0x65, 0x98, 0x73,
+	0x00, 0x3f, 0x2e, 0x5b,
+	0xff, 0x65, 0xb4, 0x73,
 	0x20, 0x36, 0x6c, 0x00,
-	0x20, 0xa0, 0x52, 0x6b,
+	0x20, 0xa0, 0x6e, 0x6b,
 	0xff, 0xb9, 0xa2, 0x0c,
 	0xff, 0x6a, 0xa2, 0x04,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x5e, 0x7b,
+	0x80, 0xeb, 0x7a, 0x7b,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x01, 0xe9, 0xa4, 0x34,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
+	0x00, 0x65, 0x78, 0x5c,
 	0xff, 0x99, 0xa4, 0x0c,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x8e, 0x7b,
+	0x80, 0xee, 0xaa, 0x7b,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0xff, 0x65, 0x32, 0x09,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x44,
+	0x00, 0x65, 0x78, 0x44,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0x54, 0x5b,
+	0x00, 0x6a, 0x70, 0x5b,
 	0xff, 0x52, 0xa2, 0x0c,
-	0x01, 0x0c, 0x9e, 0x7b,
-	0x04, 0x0c, 0x9e, 0x6b,
+	0x01, 0x0c, 0xba, 0x7b,
+	0x04, 0x0c, 0xba, 0x6b,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7a, 0x0c,
 	0xff, 0x8c, 0x10, 0x08,
@@ -489,29 +503,34 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0xff, 0x65, 0xc8, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0xba, 0x5b,
+	0x41, 0x6a, 0xd6, 0x5b,
 	0xff, 0x90, 0xe2, 0x09,
 	0x20, 0x6a, 0xd0, 0x01,
-	0x04, 0x35, 0xdc, 0x7b,
+	0x04, 0x35, 0xf8, 0x7b,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0xd8, 0x63,
-	0x00, 0x65, 0xe8, 0x43,
+	0xdc, 0xee, 0xf4, 0x63,
+	0x00, 0x65, 0x0e, 0x44,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xe2, 0x7b,
+	0x80, 0xee, 0xfe, 0x7b,
+	0x11, 0x6a, 0xdc, 0x01,
+	0x50, 0xee, 0x02, 0x64,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xdc, 0x01,
+	0x88, 0xee, 0x08, 0x64,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0xe6, 0x63,
+	0xd8, 0xee, 0x0c, 0x64,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0xea, 0x6b,
+	0x18, 0xee, 0x10, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0xba, 0x5b,
+	0x41, 0x6a, 0xd6, 0x5b,
 	0x20, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x35, 0x14, 0x6c,
+	0x04, 0x35, 0x3c, 0x6c,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
 	0xff, 0x6c, 0x32, 0x09,
@@ -522,15 +541,32 @@
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
-	0x00, 0x65, 0x00, 0x64,
+	0x00, 0x65, 0x26, 0x64,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0x04, 0x35, 0x0c, 0x7b,
-	0xa0, 0x6a, 0x20, 0x5c,
-	0x00, 0x65, 0x22, 0x5c,
-	0x00, 0x65, 0x22, 0x5c,
-	0x00, 0x65, 0x22, 0x44,
-	0xff, 0x65, 0xcc, 0x08,
+	0x00, 0x65, 0x78, 0x44,
+	0xa0, 0x6a, 0xcc, 0x00,
+	0xe8, 0x6a, 0xc8, 0x00,
+	0x01, 0x94, 0x40, 0x6c,
+	0x10, 0x94, 0x42, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x08, 0x64, 0xc8, 0x18,
+	0x00, 0x8c, 0xca, 0x18,
+	0x00, 0x65, 0x4a, 0x4c,
+	0x00, 0x65, 0x40, 0x44,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x56, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x08, 0x64, 0xc8, 0x18,
+	0x08, 0x64, 0x58, 0x64,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x78, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
@@ -538,19 +574,19 @@
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x0c,
-	0x08, 0x94, 0x30, 0x7c,
+	0x08, 0x94, 0x78, 0x7c,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x34, 0x6c,
+	0x08, 0x93, 0x7c, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0xff, 0x40, 0x74, 0x09,
 	0xff, 0x90, 0x80, 0x08,
 	0xff, 0x6a, 0x72, 0x05,
-	0xff, 0x40, 0x4c, 0x64,
-	0xff, 0x3f, 0x44, 0x64,
+	0xff, 0x40, 0x94, 0x64,
+	0xff, 0x3f, 0x8c, 0x64,
 	0xff, 0x6a, 0xca, 0x04,
 	0xff, 0x3f, 0x20, 0x09,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
+	0x00, 0xb9, 0xe6, 0x5b,
 	0xff, 0xba, 0x7e, 0x0c,
 	0xff, 0x40, 0x20, 0x09,
 	0xff, 0xba, 0x80, 0x0c,
@@ -558,12 +594,36 @@
 	0xff, 0x90, 0x7e, 0x0c,
 };
 
+static int aic7xxx_patch15_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch15_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+}
+
+static int aic7xxx_patch14_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch14_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
+}
+
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_WIDE) != 0);
+}
+
 static int aic7xxx_patch12_func(struct aic7xxx_host *p);
 
 static int
 aic7xxx_patch12_func(struct aic7xxx_host *p)
 {
-	return ((p->features & AHC_WIDE) != 0);
+	return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
 }
 
 static int aic7xxx_patch11_func(struct aic7xxx_host *p);
@@ -692,54 +752,66 @@
 	{ aic7xxx_patch7_func, 113, 1, 2 },
 	{ aic7xxx_patch0_func, 114, 1, 1 },
 	{ aic7xxx_patch1_func, 118, 1, 1 },
-	{ aic7xxx_patch1_func, 121, 3, 2 },
+	{ aic7xxx_patch1_func, 121, 3, 3 },
+	{ aic7xxx_patch11_func, 123, 1, 1 },
 	{ aic7xxx_patch0_func, 124, 5, 1 },
-	{ aic7xxx_patch1_func, 132, 2, 3 },
 	{ aic7xxx_patch7_func, 132, 1, 1 },
-	{ aic7xxx_patch0_func, 134, 3, 1 },
-	{ aic7xxx_patch11_func, 138, 1, 2 },
-	{ aic7xxx_patch0_func, 139, 1, 1 },
-	{ aic7xxx_patch7_func, 140, 7, 2 },
-	{ aic7xxx_patch0_func, 147, 1, 1 },
-	{ aic7xxx_patch1_func, 152, 14, 3 },
-	{ aic7xxx_patch11_func, 165, 1, 1 },
-	{ aic7xxx_patch0_func, 166, 9, 1 },
-	{ aic7xxx_patch7_func, 180, 2, 1 },
-	{ aic7xxx_patch7_func, 182, 1, 1 },
-	{ aic7xxx_patch11_func, 183, 6, 3 },
-	{ aic7xxx_patch1_func, 183, 2, 2 },
-	{ aic7xxx_patch0_func, 185, 4, 1 },
-	{ aic7xxx_patch7_func, 190, 1, 1 },
-	{ aic7xxx_patch7_func, 194, 20, 1 },
-	{ aic7xxx_patch1_func, 215, 3, 3 },
-	{ aic7xxx_patch11_func, 217, 1, 1 },
-	{ aic7xxx_patch0_func, 218, 5, 1 },
-	{ aic7xxx_patch11_func, 223, 1, 2 },
-	{ aic7xxx_patch0_func, 224, 9, 1 },
-	{ aic7xxx_patch12_func, 240, 1, 2 },
-	{ aic7xxx_patch0_func, 241, 1, 1 },
-	{ aic7xxx_patch4_func, 302, 1, 2 },
-	{ aic7xxx_patch0_func, 303, 1, 1 },
-	{ aic7xxx_patch2_func, 306, 1, 1 },
-	{ aic7xxx_patch1_func, 316, 3, 2 },
-	{ aic7xxx_patch0_func, 319, 5, 1 },
-	{ aic7xxx_patch12_func, 327, 1, 2 },
-	{ aic7xxx_patch0_func, 328, 1, 1 },
-	{ aic7xxx_patch5_func, 333, 1, 1 },
-	{ aic7xxx_patch11_func, 375, 15, 1 },
-	{ aic7xxx_patch1_func, 427, 7, 2 },
-	{ aic7xxx_patch0_func, 434, 8, 1 },
-	{ aic7xxx_patch1_func, 443, 4, 2 },
-	{ aic7xxx_patch0_func, 447, 6, 1 },
-	{ aic7xxx_patch1_func, 453, 4, 2 },
-	{ aic7xxx_patch0_func, 457, 3, 1 },
-	{ aic7xxx_patch10_func, 467, 10, 1 },
-	{ aic7xxx_patch1_func, 486, 17, 4 },
-	{ aic7xxx_patch9_func, 494, 4, 2 },
-	{ aic7xxx_patch0_func, 498, 2, 1 },
-	{ aic7xxx_patch0_func, 503, 33, 1 },
-	{ aic7xxx_patch10_func, 536, 4, 1 },
-	{ aic7xxx_patch5_func, 540, 2, 1 },
-	{ aic7xxx_patch5_func, 543, 9, 1 },
+	{ aic7xxx_patch9_func, 133, 1, 1 },
+	{ aic7xxx_patch10_func, 134, 3, 1 },
+	{ aic7xxx_patch7_func, 137, 3, 2 },
+	{ aic7xxx_patch0_func, 140, 2, 1 },
+	{ aic7xxx_patch7_func, 142, 5, 2 },
+	{ aic7xxx_patch0_func, 147, 3, 1 },
+	{ aic7xxx_patch7_func, 150, 1, 2 },
+	{ aic7xxx_patch0_func, 151, 2, 1 },
+	{ aic7xxx_patch1_func, 153, 15, 4 },
+	{ aic7xxx_patch11_func, 166, 1, 2 },
+	{ aic7xxx_patch0_func, 167, 1, 1 },
+	{ aic7xxx_patch0_func, 168, 10, 1 },
+	{ aic7xxx_patch7_func, 181, 1, 2 },
+	{ aic7xxx_patch0_func, 182, 2, 1 },
+	{ aic7xxx_patch7_func, 184, 18, 1 },
+	{ aic7xxx_patch1_func, 202, 3, 3 },
+	{ aic7xxx_patch7_func, 204, 1, 1 },
+	{ aic7xxx_patch0_func, 205, 4, 1 },
+	{ aic7xxx_patch7_func, 210, 2, 1 },
+	{ aic7xxx_patch7_func, 215, 13, 3 },
+	{ aic7xxx_patch12_func, 218, 1, 1 },
+	{ aic7xxx_patch12_func, 219, 4, 1 },
+	{ aic7xxx_patch1_func, 229, 3, 3 },
+	{ aic7xxx_patch11_func, 231, 1, 1 },
+	{ aic7xxx_patch0_func, 232, 5, 1 },
+	{ aic7xxx_patch11_func, 237, 1, 2 },
+	{ aic7xxx_patch0_func, 238, 9, 1 },
+	{ aic7xxx_patch13_func, 254, 1, 2 },
+	{ aic7xxx_patch0_func, 255, 1, 1 },
+	{ aic7xxx_patch4_func, 316, 1, 2 },
+	{ aic7xxx_patch0_func, 317, 1, 1 },
+	{ aic7xxx_patch2_func, 320, 1, 1 },
+	{ aic7xxx_patch1_func, 330, 3, 2 },
+	{ aic7xxx_patch0_func, 333, 5, 1 },
+	{ aic7xxx_patch13_func, 341, 1, 2 },
+	{ aic7xxx_patch0_func, 342, 1, 1 },
+	{ aic7xxx_patch5_func, 347, 1, 1 },
+	{ aic7xxx_patch11_func, 389, 15, 2 },
+	{ aic7xxx_patch14_func, 402, 1, 1 },
+	{ aic7xxx_patch1_func, 441, 7, 2 },
+	{ aic7xxx_patch0_func, 448, 8, 1 },
+	{ aic7xxx_patch1_func, 457, 4, 2 },
+	{ aic7xxx_patch0_func, 461, 6, 1 },
+	{ aic7xxx_patch1_func, 467, 4, 2 },
+	{ aic7xxx_patch0_func, 471, 3, 1 },
+	{ aic7xxx_patch10_func, 481, 10, 1 },
+	{ aic7xxx_patch1_func, 500, 22, 5 },
+	{ aic7xxx_patch11_func, 508, 4, 1 },
+	{ aic7xxx_patch7_func, 512, 7, 3 },
+	{ aic7xxx_patch15_func, 512, 5, 2 },
+	{ aic7xxx_patch0_func, 517, 2, 1 },
+	{ aic7xxx_patch10_func, 522, 50, 3 },
+	{ aic7xxx_patch14_func, 543, 17, 2 },
+	{ aic7xxx_patch0_func, 560, 4, 1 },
+	{ aic7xxx_patch10_func, 572, 4, 1 },
+	{ aic7xxx_patch5_func, 576, 2, 1 },
+	{ aic7xxx_patch5_func, 579, 9, 1 },
 
 };
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.4.6/linux/drivers/scsi/aic7xxx_old.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Thu Jul  5 11:28:17 2001
@@ -256,7 +256,7 @@
 #include <scsi/scsicam.h>
 
 #include <linux/stat.h>
-#include <linux/malloc.h>        /* for kmalloc() */
+#include <linux/slab.h>        /* for kmalloc() */
 
 #include <linux/config.h>        /* for CONFIG_PCI */
 
@@ -266,7 +266,7 @@
  */
 #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
 
-#define AIC7XXX_C_VERSION  "5.2.1"
+#define AIC7XXX_C_VERSION  "5.2.4"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -311,8 +311,8 @@
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
-#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
 #else
 #define AIC7XXX_CMDS_PER_DEVICE 8
 #endif
@@ -323,7 +323,7 @@
  * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
  * NOTE: This does affect performance since it has to maintain statistics.
  */
-#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS
+#ifdef CONFIG_AIC7XXX_PROC_STATS
 #define AIC7XXX_PROC_STATS
 #endif
 
@@ -347,7 +347,7 @@
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
 #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
                               0, 0, 0, 0, 0, 0, 0, 0}
 #else
@@ -706,13 +706,14 @@
 /*28*/  unsigned int pad;           /*
                                      * Unused by the kernel, but we require
                                      * the padding so that the array of
-                                     * hardware SCBs is alligned on 32 byte
+                                     * hardware SCBs is aligned on 32 byte
                                      * boundaries so the sequencer can index
                                      */
 };
 
 typedef enum {
         SCB_FREE                = 0x0000,
+        SCB_DTR_SCB             = 0x0001,
         SCB_WAITINGQ            = 0x0002,
         SCB_ACTIVE              = 0x0004,
         SCB_SENSE               = 0x0008,
@@ -830,6 +831,17 @@
 	unsigned int	       dma_len;	      /* DMA length */
 };
 
+typedef enum {
+  AHC_BUG_NONE            = 0x0000,
+  AHC_BUG_TMODE_WIDEODD   = 0x0001,
+  AHC_BUG_AUTOFLUSH       = 0x0002,
+  AHC_BUG_CACHETHEN       = 0x0004,
+  AHC_BUG_CACHETHEN_DIS   = 0x0008,
+  AHC_BUG_PCI_2_1_RETRY   = 0x0010,
+  AHC_BUG_PCI_MWI         = 0x0020,
+  AHC_BUG_SCBCHAN_UPLOAD  = 0x0040,
+} ahc_bugs;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
         Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
@@ -942,7 +954,6 @@
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
   scb_data_type           *scb_data;
-  volatile unsigned short  needdv;
   volatile unsigned short  needppr;
   volatile unsigned short  needsdtr;
   volatile unsigned short  needwdtr;
@@ -973,10 +984,9 @@
 #define  BUS_DEVICE_RESET_PENDING       0x02
 #define  DEVICE_RESET_DELAY             0x04
 #define  DEVICE_PRINT_DTR               0x08
-#define  DEVICE_PARITY_ERROR            0x10
-#define  DEVICE_WAS_BUSY                0x20
-#define  DEVICE_SCSI_3                  0x40
-#define  DEVICE_SCANNED                 0x80
+#define  DEVICE_WAS_BUSY                0x10
+#define  DEVICE_SCSI_3                  0x20
+#define  DEVICE_DTR_SCANNED             0x40
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
@@ -989,10 +999,6 @@
   spinlock_t               spin_lock;
   volatile unsigned char   cpu_lock_count[NR_CPUS];
 
-  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
-
-  unsigned int             dev_checksum[MAX_TARGETS];
-  
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
   unsigned char            dev_max_queue_depth[MAX_TARGETS];
@@ -1040,6 +1046,7 @@
   int                      host_no;          /* SCSI host number */
   unsigned long            mbase;            /* I/O memory address */
   ahc_chip                 chip;             /* chip type */
+  ahc_bugs                 bugs;
   dma_addr_t		   fifo_dma;	     /* DMA handle for fifo arrays */
 
   /*
@@ -2821,138 +2828,98 @@
   {
     p->flags &= ~AHC_ABORT_PENDING;
   }
-  if (scb->flags & SCB_RESET)
+  if (scb->flags & (SCB_RESET|SCB_ABORT))
   {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+    cmd->result |= (DID_RESET << 16);
   }
-  else if (scb->flags & SCB_ABORT)
-  {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
-  }
-  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+
+  if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
   {
     if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
     {
-      char *buffer;
-      
+    
       p->dev_flags[tindex] |= DEVICE_PRESENT;
-      if(cmd->use_sg)
-      {
-        struct scatterlist *sg;
-
-        sg = (struct scatterlist *)cmd->request_buffer;
-        buffer = (char *)sg[0].address;
-      }
-      else
-      {
-        buffer = (char *)cmd->request_buffer;
-      }
 #define WIDE_INQUIRY_BITS 0x60
 #define SYNC_INQUIRY_BITS 0x10
 #define SCSI_VERSION_BITS 0x07
 #define SCSI_DT_BIT       0x04
-      if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
-           (p->features & AHC_WIDE) )
-      {
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
-      }
-      else
-      {
-        p->needwdtr &= ~(1<<tindex);
-        p->needwdtr_copy &= ~(1<<tindex);
-        pause_sequencer(p);
-        aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
-                          MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
-                                                   AHC_TRANS_GOAL |
-                                                   AHC_TRANS_CUR) );
-        unpause_sequencer(p, FALSE);
-      }
-      if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
-            p->transinfo[tindex].user_offset )
-      {
-        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
-        if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+      if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
+        char *buffer;
+
+        if(cmd->use_sg)
+        {
+          struct scatterlist *sg;
+
+          sg = (struct scatterlist *)cmd->request_buffer;
+          buffer = (char *)sg[0].address;
+        }
+        else
+        {
+          buffer = (char *)cmd->request_buffer;
+        }
+
+
+        if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+             (p->features & AHC_WIDE) )
+        {
+          p->needwdtr |= (1<<tindex);
+          p->needwdtr_copy |= (1<<tindex);
+          p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+        }
         else
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
-               (buffer[56] & SCSI_DT_BIT) ||
-	       (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
-               (p->transinfo[tindex].user_period <= 9) &&
-               (p->transinfo[tindex].user_options) )
         {
-          p->needppr |= (1<<tindex);
-          p->needppr_copy |= (1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
           p->needwdtr &= ~(1<<tindex);
           p->needwdtr_copy &= ~(1<<tindex);
-          p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          pause_sequencer(p);
+          aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+                            MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+                                                     AHC_TRANS_GOAL |
+                                                     AHC_TRANS_CUR) );
+          unpause_sequencer(p, FALSE);
         }
-        else
+        if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+              p->transinfo[tindex].user_offset )
         {
-          p->needsdtr |= (1<<tindex);
-          p->needsdtr_copy |= (1<<tindex);
-          p->transinfo[tindex].goal_period = 
-            MAX(10, p->transinfo[tindex].goal_period);
-          p->transinfo[tindex].goal_options = 0;
+          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+          p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+          if (p->features & AHC_ULTRA2)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+          else
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+          if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
+                 (buffer[56] & SCSI_DT_BIT) ||
+                 (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+                 (p->transinfo[tindex].user_period <= 9) &&
+                 (p->transinfo[tindex].user_options) )
+          {
+            p->needppr |= (1<<tindex);
+            p->needppr_copy |= (1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+            p->needwdtr &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
+            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          }
+          else
+          {
+            p->needsdtr |= (1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
+            p->transinfo[tindex].goal_period = 
+              MAX(10, p->transinfo[tindex].goal_period);
+            p->transinfo[tindex].goal_options = 0;
+          }
         }
-      }
-      else
-      {
-        p->needsdtr &= ~(1<<tindex);
-        p->needsdtr_copy &= ~(1<<tindex);
-        p->transinfo[tindex].goal_period = 255;
-        p->transinfo[tindex].goal_offset = 0;
-        p->transinfo[tindex].goal_options = 0;
-      }
-      /*
-       * This is needed to work around a sequencer bug for now.  Regardless
-       * of the controller in use, if we have a Quantum drive, we need to
-       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
-       * of the sequencer, this code will get yanked.
-       */
-      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
-         p->transinfo[tindex].goal_options )
-      {
-        p->transinfo[tindex].goal_period = 
-          MAX(p->transinfo[tindex].goal_period, 10);
-        p->transinfo[tindex].goal_options = 0;
-        p->needppr &= ~(1<<tindex);
-        p->needppr_copy &= ~(1<<tindex);
-        p->needsdtr |= (1<<tindex);
-        p->needsdtr_copy |= (1<<tindex);
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-      }
-      /*
-       * Get the INQUIRY checksum.  We use this on Ultra 160/m
-       * and older devices both.  It allows us to drop speed on any bus type
-       * while at the same time giving us the needed domain validation for
-       * Ultra 160/m
-       *
-       * Note: We only get the checksum and set the SCANNED bit if this is
-       * one of our dtr commands.  If we don't do this, then we end up
-       * getting bad checksum results on the mid-level SCSI code's INQUIRY
-       * commands.
-       */
-      if(p->dev_dtr_cmnd[tindex] == cmd) {
-        unsigned int checksum = 0;
-        int *ibuffer;
-        int i=0;
-
-        ibuffer = (int *)buffer;
-        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+        else
         {
-          checksum += ibuffer[i];
+          p->needsdtr &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->transinfo[tindex].goal_period = 255;
+          p->transinfo[tindex].goal_offset = 0;
+          p->transinfo[tindex].goal_options = 0;
         }
-        p->dev_checksum[tindex] = checksum;
-        p->dev_flags[tindex] |= DEVICE_SCANNED;
+        p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
         p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
       }
 #undef WIDE_INQUIRY_BITS
@@ -2961,7 +2928,8 @@
 #undef SCSI_DT_BIT
     }
   }
-  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+
+  if ((scb->flags & SCB_MSGOUT_BITS) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
@@ -2981,7 +2949,6 @@
 
     if (scb->flags & SCB_MSGOUT_WDTR)
     {
-      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3000,7 +2967,6 @@
     }
     if (scb->flags & SCB_MSGOUT_SDTR)
     {
-      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3020,7 +2986,6 @@
     }
     if (scb->flags & SCB_MSGOUT_PPR)
     {
-      p->dtr_pending &= ~mask;
       if(message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3045,6 +3010,7 @@
       }
     }
   }
+
   queue_depth = p->dev_temp_queue_depth[tindex];
   if (queue_depth >= p->dev_active_cmds[tindex])
   {
@@ -3078,9 +3044,18 @@
       }
     }
   }
-  if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
+  if (!(scb->tag_action))
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
+                              /* unbusy */ TRUE);
+    if (p->tagenable & (1<<tindex))
+    {
+      p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+    }
+  }
+  if(scb->flags & SCB_DTR_SCB)
   {
-    p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+    p->dtr_pending &= ~(1 << tindex);
   }
   p->dev_active_cmds[tindex]--;
   p->activescbs--;
@@ -3189,6 +3164,14 @@
         printk(INFO_LEAD "Aborting scb %d\n",
              p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
       found++;
+      /*
+       * Clear any residual information since the normal aic7xxx_done() path
+       * doesn't touch the residuals.
+       */
+      scb->hscb->residual_SG_segment_count = 0;
+      scb->hscb->residual_data_count[0] = 0;
+      scb->hscb->residual_data_count[1] = 0;
+      scb->hscb->residual_data_count[2] = 0;
       aic7xxx_done(p, scb);
     }
   }
@@ -3401,8 +3384,22 @@
   active_scb = aic_inb(p, SCBPTR);
 
   if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+  {
     printk(INFO_LEAD "Reset device, active_scb %d\n",
          p->host_no, channel, target, lun, active_scb);
+    printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, channel, target, lun,
+         (p->features & AHC_ULTRA2) ?  aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
   /*
    * Deal with the busy target and linked next issues.
    */
@@ -3446,11 +3443,11 @@
       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
       if ( tag == SCB_LIST_NULL )
       {
         p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
-        p->dev_expires[i] = jiffies + (4 * HZ);
+        p->dev_expires[i] = jiffies + (1 * HZ);
         p->dev_timer_active |= (0x01 << i);
         p->dev_last_queue_full_count[i] = 0;
         p->dev_last_queue_full[i] = 0;
@@ -3495,7 +3492,7 @@
           prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
         }
       }
-      if ( j > (p->scb_data->maxscbs + 1) )
+      if ( j > (p->scb_data->numscbs + 1) )
       {
         if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
           printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -3554,7 +3551,7 @@
         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
-    if ( j > (p->scb_data->maxscbs + 1) )
+    if ( j > (p->scb_data->numscbs + 1) )
     {
       if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
         printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -4300,11 +4297,25 @@
     if (actual < cmd->underflow)
     {
       if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+      {
         printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
           "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
           (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
           hscb->residual_SG_segment_count);
+        printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
+          hscb->target_status);
+      }
+      /*
+       * In 2.4, only send back the residual information, don't flag this
+       * as an error.  Before 2.4 we had to flag this as an error because
+       * the mid layer didn't check residual data counts to see if the
+       * command needs retried.
+       */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+      cmd->resid = scb->sg_length - actual;
+#else
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+#endif
       aic7xxx_status(cmd) = hscb->target_status;
     }
   }
@@ -4623,7 +4634,6 @@
            */
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
             (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
@@ -4643,8 +4653,7 @@
           */
           p->needsdtr &= ~target_mask;
           p->needsdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
-          scb->flags &= ~SCB_MSGOUT_SDTR;
+          scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
             (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -4778,6 +4787,8 @@
                 aic7xxx_error(cmd) = DID_OK;
                 break;
               }  /* first time sense, no errors */
+              printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
+                     "an error.\n", p->host_no, CTL_OF_SCB(scb));
               aic7xxx_error(cmd) = DID_ERROR;
               scb->flags &= ~SCB_SENSE;
               break;
@@ -5136,12 +5147,21 @@
           printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
             (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
             scb->sg_length, scb->sg_count);
-          for (i = 0; i < scb->sg_count; i++)
+          printk(KERN_WARNING "  Raw SCSI Command: 0x");
+          for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
+          {
+            printk("%02x ", scb->cmd->cmnd[i]);
+          }
+          printk("\n");
+          if(aic7xxx_verbose > 0xffff)
           {
-            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+            for (i = 0; i < scb->sg_count; i++)
+            {
+              printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
                  i, 
                  le32_to_cpu(scb->sg_list[i].address),
                  le32_to_cpu(scb->sg_list[i].length) );
+            }
           }
           aic7xxx_error(scb->cmd) = DID_ERROR;
         }
@@ -5156,7 +5176,7 @@
         unsigned char resid_sgcnt, index;
         unsigned char scb_index = aic_inb(p, SCB_TAG);
         unsigned int cur_addr, resid_dcnt;
-        unsigned int native_addr, native_length;
+        unsigned int native_addr, native_length, sg_addr;
         int i;
 
         if(scb_index > p->scb_data->numscbs)
@@ -5176,6 +5196,9 @@
                  scb->flags, (unsigned long)scb->cmd);
           break;
         }
+        if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
+                 "pointer.\n", p->host_no, CTL_OF_SCB(scb));
 
         /*
          * We have a valid scb to use on this WIDE_RESIDUE message, so
@@ -5188,132 +5211,87 @@
          */
         cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
           (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+        sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
+          (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24);
         resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
         resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
           (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
           (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
-        index = scb->sg_count - (resid_sgcnt + 1);
+        index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
         native_addr = le32_to_cpu(scb->sg_list[index].address);
         native_length = le32_to_cpu(scb->sg_list[index].length);
         /*
-         * Make sure this is a valid sg_seg for the given pointer
+         * If resid_dcnt == native_length, then we just loaded this SG
+         * segment and we need to back it up one...
          */
-        if(cur_addr < native_addr ||
-           cur_addr > (native_addr + native_length + 1))
-        {
-          printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
-                 p->host_no, CTL_OF_SCB(scb), cur_addr);
-          if(index > 0)
-            printk(WARN_LEAD "  sg_address[-1]:0x%x sg_length[-1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index - 1].address),
-                   le32_to_cpu(scb->sg_list[index - 1].length));
-          printk(WARN_LEAD "  sg_address:0x%x sg_length:%d\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 native_addr, native_length);
-          if(resid_sgcnt > 1)
-            printk(WARN_LEAD "  sg_address[1]:0x%x sg_length[1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index + 1].address),
-                   le32_to_cpu(scb->sg_list[index + 1].length));
-          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 cur_addr, resid_dcnt);
-          break;
-        }
-
-        if( (resid_sgcnt == 0) &&
-            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
-        {
-          /*
-           * We are at the end of the transfer and this is about a byte
-           * we ignored already (because the sequencer knew this was
-           * the last segment and set the adapter to ignore any wide
-           * residue bytes that might come through, which is only done
-           * on the last scatter gather segment of transfers).
-           */
-          break;
-        }
-        else if(cur_addr == native_addr)
+        if(resid_dcnt == native_length)
         {
-          /*
-           * If our current address matches the sg_seg->address then we
-           * have to back up the sg array to the previous segment and set
-           * it up to have only one byte of transfer left to go.
-           */
           if(index == 0)
           {
-            printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
-                   "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+            /*
+             * Oops, this isn't right, we can't back up to before the
+             * beginning.  This must be a bogus message, ignore it.
+             */
             break;
           }
-          resid_sgcnt++;
-          index--;
-          cur_addr = le32_to_cpu(scb->sg_list[index].address) + 
-            le32_to_cpu(scb->sg_list[index].length) - 1;
-          native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
-            | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
-          native_addr -= SG_SIZEOF;
-          aic_outb(p, resid_sgcnt, SG_COUNT);
-          aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
-          aic_outb(p, native_addr & 0xff, SG_NEXT);
-          aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
-          aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
-          aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
-          aic_outb(p, 1, SCB_RESID_DCNT); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 1); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 2); 
-          aic_outb(p, 1, HCNT); 
-          aic_outb(p, 0, HCNT + 1); 
-          aic_outb(p, 0, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          resid_dcnt = 1;
+          resid_sgcnt += 1;
+          native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
+          native_length = le32_to_cpu(scb->sg_list[index - 1].length);
+          cur_addr = native_addr + (native_length - 1);
+          sg_addr -= sizeof(struct hw_scatterlist);
         }
         else
         {
           /*
-           * Back the data pointer up by one and add one to the remaining
-           * byte count.  Then store that in the HCNT and HADDR registers.
+           * resid_dcnt != native_length, so we are in the middle of a SG
+           * element.  Back it up one byte and leave the rest alone.
            */
-          cur_addr--;
-          resid_dcnt++;
-          aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); 
-          aic_outb(p, resid_dcnt & 0xff, HCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          resid_dcnt += 1;
+          cur_addr -= 1;
         }
+        
+        /*
+         * Output the new addresses and counts to the right places on the
+         * card.
+         */
+        aic_outb(p, resid_sgcnt, SG_COUNT);
+        aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+        aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
+        aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
+        aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
+        aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
+        aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+        aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+        aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+
         /*
-         * The sequencer actually wants to find the new address and byte
-         * count in the SHCNT and SHADDR register sets.  These registers
-         * are a shadow of the regular HCNT and HADDR registers.  On the
-         * Ultra2 controllers, these registers are read only and the way
-         * we have to set their values is to put the values we want into
-         * the HCNT and HADDR registers and then output PRELOADEN into
-         * the DFCNTRL register which causes the card to latch the current
-         * values in the HADDR and HCNT registers and drop it through to
-         * the shadow registers.  On older cards we copy them directly
-         * across by hand.
+         * The sequencer actually wants to find the new address
+         * in the SHADDR register set.  On the Ultra2 and later controllers
+         * this register set is readonly.  In order to get the right number
+         * into the register, you actually have to enter it in HADDR and then
+         * use the PRELOADEN bit of DFCNTRL to drop it through from the
+         * HADDR register to the SHADDR register.  On non-Ultra2 controllers,
+         * we simply write it direct.
          */
         if(p->features & AHC_ULTRA2)
         {
-          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-          i=0;
+          /*
+           * We might as well be accurate and drop both the resid_dcnt and
+           * cur_addr into HCNT and HADDR and have both of them drop
+           * through to the shadow layer together.
+           */
+          aic_outb(p, resid_dcnt & 0xff, HCNT);
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+          aic_outb(p, cur_addr & 0xff, HADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
           udelay(1);
-          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
-          {
-            udelay(1);
-          }
           aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
           i=0;
-          udelay(1);
           while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
           {
             udelay(1);
@@ -5321,9 +5299,6 @@
         }
         else
         {
-          aic_outb(p, resid_dcnt & 0xff, STCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
           aic_outb(p, cur_addr & 0xff, SHADDR);
           aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
           aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
@@ -5332,15 +5307,82 @@
       }
       break;
 
-        
-#if AIC7XXX_NOT_YET 
-    case TRACEPOINT:
+    case SEQ_SG_FIXUP:
+    {
+      unsigned char scb_index, tmp;
+      int sg_addr, sg_length;
+
+      scb_index = aic_inb(p, SCB_TAG);
+
+      if(scb_index > p->scb_data->numscbs)
       {
-        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
-               channel, target, lun);
+        printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
+          p->host_no, -1, -1, -1);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, -1, -1, -1,
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        /*
+         * XXX: Add error handling here
+         */
+        break;
       }
-      break;
+      scb = p->scb_data->scb_array[scb_index];
+      if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+      {
+        printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
+               "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
+               scb->flags, (unsigned int)scb->cmd);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        break;
+      }
+      if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
+               CTL_OF_SCB(scb));
+      /*
+       * Advance the SG pointer to the next element in the list
+       */
+      tmp = aic_inb(p, SG_NEXT);
+      tmp += SG_SIZEOF;
+      aic_outb(p, tmp, SG_NEXT);
+      if( tmp < SG_SIZEOF )
+        aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
+      tmp = aic_inb(p, SG_COUNT) - 1;
+      aic_outb(p, tmp, SG_COUNT);
+      sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
+      sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
+      /*
+       * Now stuff the element we just advanced past down onto the
+       * card so it can be stored in the residual area.
+       */
+      aic_outb(p, sg_addr & 0xff, HADDR);
+      aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
+      aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
+      aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
+      aic_outb(p, sg_length & 0xff, HCNT);
+      aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
+      aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
+      aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
+      aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+      while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
+      while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
+    }
+    break;
 
+#if AIC7XXX_NOT_YET 
     case TRACEPOINT2:
       {
         printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
@@ -5385,6 +5427,10 @@
   unsigned char target_scsirate, tindex;
   unsigned short target_mask;
   unsigned char target, channel, lun;
+  unsigned char bus_width, new_bus_width;
+  unsigned char trans_options, new_trans_options;
+  unsigned int period, new_period, offset, new_offset, maxsync;
+  struct aic7xxx_syncrate *syncrate;
 
   target = scb->cmd->target;
   channel = scb->cmd->channel;
@@ -5408,6 +5454,35 @@
   }
 
   /*
+   * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+   * using the SDTR messages.  We need the PPR messages to enable the
+   * higher speeds that include things like Dual Edge clocking.
+   */
+  if (p->features & AHC_ULTRA2)
+  {
+    if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+         !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+    {
+      if (p->features & AHC_ULTRA3)
+        maxsync = AHC_SYNCRATE_ULTRA3;
+      else
+        maxsync = AHC_SYNCRATE_ULTRA2;
+    }
+    else
+    {
+      maxsync = AHC_SYNCRATE_ULTRA;
+    }
+  }
+  else if (p->features & AHC_ULTRA)
+  {
+    maxsync = AHC_SYNCRATE_ULTRA;
+  }
+  else
+  {
+    maxsync = AHC_SYNCRATE_FAST;
+  }
+
+  /*
    * Just accept the length byte outright and perform
    * more checking once we know the message type.
    */
@@ -5418,9 +5493,6 @@
     {
       case MSG_EXT_SDTR:
       {
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset, options;
-        struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
         {
@@ -5433,35 +5505,18 @@
           break;
         }
 
-        period = p->msg_buf[3];
-        saved_offset = offset = p->msg_buf[4];
-        options = 0;
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[4];
+        trans_options = new_trans_options = 0;
+        bus_width = new_bus_width = target_scsirate & WIDEXFER;
 
         /*
-         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
-         * using the SDTR messages.  We need the PPR messages to enable the
-         * higher speeds that include things like Dual Edge clocking.
+         * If our current max syncrate is in the Ultra3 range, bump it back
+         * down to Ultra2 since we can't negotiate DT transfers using SDTR
          */
-        if (p->features & AHC_ULTRA2)
-        {
-          if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-               !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA;
-          }
-        }
-        else if (p->features & AHC_ULTRA)
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_FAST;
-        }
+        if(maxsync == AHC_SYNCRATE_ULTRA3)
+          maxsync = AHC_SYNCRATE_ULTRA2;
+
         /*
          * We might have a device that is starting negotiation with us
          * before we can start up negotiation with it....be prepared to
@@ -5471,88 +5526,116 @@
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
-              !(p->needsdtr_copy & target_mask) &&
-               (p->transinfo[tindex].user_offset) )
+          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
           {
             /*
-             * Not only is the device starting this up, but it also hasn't
-             * been scanned yet, so this would likely be our TUR or our
-             * INQUIRY command at scan time, so we need to use the
-             * settings from the SEEPROM if they existed.  Of course, even
-             * if we didn't find a SEEPROM, we stuffed default values into
-             * the user settings anyway, so use those in all cases.
+             * We shouldn't get here unless this is a narrow drive, wide
+             * devices should trigger this same section of code in the WDTR
+             * handler first instead.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            if(p->features & AHC_ULTRA2)
-            {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-            }
-            else if (p->transinfo[tindex].cur_width)
+            p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+            p->transinfo[tindex].goal_options = 0;
+            if(p->transinfo[tindex].user_offset)
             {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              p->needsdtr_copy |= target_mask;
+              p->transinfo[tindex].goal_period =
+                MAX(10,p->transinfo[tindex].user_period);
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
             }
             else
             {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              p->needsdtr_copy &= ~target_mask;
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
             }
-            p->needsdtr_copy |= target_mask;
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if ((p->needsdtr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
           }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive SDTR message from "
                    "target.\n", p->host_no, CTL_OF_SCB(scb));
           }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
+          /*
+           * Validate the values the device passed to us against our SEEPROM
+           * settings.  We don't have to do this if we aren't replying since
+           * the device isn't allowed to send values greater than the ones
+           * we first sent to it.
+           */
+          new_period = MAX(period, p->transinfo[tindex].goal_period);
+          new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
         }
-  
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
-        aic7xxx_validate_offset(p, syncrate, &offset,
-                                target_scsirate & WIDEXFER);
-        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ 
+        /*
+         * Use our new_period, new_offset, bus_width, and card options
+         * to determine the actual syncrate settings
+         */
+        syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                         &trans_options);
+        aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
 
         /*
-         * Did we drop to async?  Or are we sending a reply?  If we are,
-         * then we have to make sure that the reply value reflects the proper
-         * settings so we need to set the goal values according to what
-         * we need to send.
+         * Did we drop to async?  If so, send a reply regardless of whether
+         * or not we initiated this negotiation.
          */
-        if ( (offset != saved_offset) ||
-             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
+        if ((new_offset == 0) && (new_offset != offset))
         {
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
-                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          p->needsdtr_copy &= ~target_mask;
+          reply = TRUE;
         }
         
         /*
-         * Did we start this, if not, or if we went to low and had to
+         * Did we start this, if not, or if we went too low and had to
          * go async, then send an SDTR back to the target
          */
-        p->needsdtr &= ~target_mask;
-        p->dtr_pending &= ~target_mask;
-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
-             (offset != saved_offset) )
+        if(reply)
         {
-          reply = TRUE;
-          p->dtr_pending |= target_mask;
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
+        else
+        {
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          p->needsdtr &= ~target_mask;
+        }
         done = TRUE;
         break;
       }
       case MSG_EXT_WDTR:
       {
-        unsigned char bus_width;
           
         if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
         {
@@ -5565,7 +5648,8 @@
           break;
         }
 
-        bus_width = p->msg_buf[3];
+        bus_width = new_bus_width = p->msg_buf[3];
+
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
              (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
         {
@@ -5584,7 +5668,7 @@
             } /* We fall through on purpose */
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
               p->needwdtr_copy &= ~target_mask;
               break;
             }
@@ -5593,29 +5677,40 @@
               break;
             }
           }
-          p->dtr_pending &= ~target_mask;
           p->needwdtr &= ~target_mask;
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
         else
         {
-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+          if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
           {
             /* 
              * Well, we now know the WDTR and SYNC caps of this device since
              * it contacted us first, mark it as such and copy the user stuff
              * over to the goal stuff.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
+            if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
+            {
+              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+              p->needwdtr_copy |= target_mask;
+            }
+            
+            /*
+             * Devices that support DT transfers don't start WDTR requests
+             */
+            p->transinfo[tindex].goal_options = 0;
+
             if(p->transinfo[tindex].user_offset)
             {
+              p->needsdtr_copy |= target_mask;
+              p->transinfo[tindex].goal_period =
+                MAX(10,p->transinfo[tindex].user_period);
               if(p->features & AHC_ULTRA2)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].user_width &&
-                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
-                       p->features & AHC_WIDE )
+              else if( p->transinfo[tindex].goal_width )
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
               }
@@ -5623,48 +5718,76 @@
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
               }
+            } else {
+              p->needsdtr_copy &= ~target_mask;
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
             }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->needwdtr_copy |= target_mask;
-            p->needsdtr_copy |= target_mask;
+            
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
           }
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          else if ((p->needwdtr_copy & target_mask) == 0)
           {
-            printk(INFO_LEAD "Received pre-emptive WDTR message from "
-                   "target.\n", p->host_no, CTL_OF_SCB(scb));
-          }
-          switch(bus_width)
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
+          }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
-            default:
+            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          switch(bus_width)
+          {
+            case MSG_EXT_WDTR_BUS_16_BIT:
             {
               if ( (p->features & AHC_WIDE) &&
                    (p->transinfo[tindex].goal_width ==
                     MSG_EXT_WDTR_BUS_16_BIT) )
               {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
                 break;
               }
             } /* Fall through if we aren't a wide card */
+            default:
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
               p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
               break;
             }
           }
-          reply = TRUE;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_WDTR;
           p->needwdtr &= ~target_mask;
-          p->dtr_pending |= target_mask;
+          if((p->dtr_pending & target_mask) == 0)
+          {
+            /* there is no other command with SCB_DTR_SCB already set that will
+             * trigger the release of the dtr_pending bit.  Both set the bit
+             * and set scb->flags |= SCB_DTR_SCB
+             */
+            p->dtr_pending |= target_mask;
+            scb->flags |= SCB_DTR_SCB;
+          }
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
-        aic7xxx_set_width(p, target, channel, lun, bus_width,
-                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         
         /*
          * By virtue of the SCSI spec, a WDTR message negates any existing
@@ -5681,10 +5804,6 @@
       }
       case MSG_EXT_PPR:
       {
-        unsigned char bus_width, trans_options, new_trans_options;
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset;
-        struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
         {
@@ -5697,9 +5816,9 @@
           break;
         }
 
-        period = p->msg_buf[3];
-        offset = saved_offset = p->msg_buf[5];
-        bus_width = p->msg_buf[6];
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[5];
+        bus_width = new_bus_width = p->msg_buf[6];
         trans_options = new_trans_options = p->msg_buf[7] & 0xf;
 
         if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -5709,22 +5828,6 @@
                  trans_options);
         }
 
-        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-        {
-          if(p->features & AHC_ULTRA3)
-          {
-            maxsync = AHC_SYNCRATE_ULTRA3;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
         /*
          * We might have a device that is starting negotiation with us
          * before we can start up negotiation with it....be prepared to
@@ -5733,13 +5836,22 @@
          */
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
-        {
-          reply = TRUE;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_PPR;
-	  p->dev_flags[tindex] |= DEVICE_SCSI_3;
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
-          {
+        { 
+          /* Have we scanned the device yet? */
+          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
+          {
+            /* The device is electing to use PPR messages, so we will too until
+             * we know better */
+            p->needppr |= target_mask;
+            p->needppr_copy |= target_mask;
+            p->needsdtr &= ~target_mask;
+            p->needsdtr_copy &= ~target_mask;
+            p->needwdtr &= ~target_mask;
+            p->needwdtr_copy &= ~target_mask;
+          
+            /* We know the device is SCSI-3 compliant due to PPR */
+            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          
             /*
              * Not only is the device starting this up, but it also hasn't
              * been scanned yet, so this would likely be our TUR or our
@@ -5748,15 +5860,19 @@
              * if we didn't find a SEEPROM, we stuffed default values into
              * the user settings anyway, so use those in all cases.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
             if(p->transinfo[tindex].user_offset)
             {
+              p->transinfo[tindex].goal_period =
+                p->transinfo[tindex].user_period;
+              p->transinfo[tindex].goal_options =
+                p->transinfo[tindex].user_options;
               if(p->features & AHC_ULTRA2)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].user_width &&
+              else if( p->transinfo[tindex].goal_width &&
                        (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
                        p->features & AHC_WIDE )
               {
@@ -5767,117 +5883,142 @@
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
               }
             }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
+            else
+            {
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
+              p->transinfo[tindex].goal_options = 0;
+            }
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
           }
+          else if ((p->needppr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a PPR with this target (for whatever reason),
+             * so reject this incoming PPR
+             */
+            reject = TRUE;
+            break;
+          }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive PPR message from "
                    "target.\n", p->host_no, CTL_OF_SCB(scb));
           }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
-          if ( p->transinfo[tindex].goal_options == 0 )
-            new_trans_options = 0;
-          switch(bus_width)
+
+        }
+
+        switch(bus_width)
+        {
+          case MSG_EXT_WDTR_BUS_16_BIT:
           {
-            default:
+            if ( (p->transinfo[tindex].goal_width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE)
             {
-              if ( (p->features & AHC_WIDE) &&
-                   (p->transinfo[tindex].goal_width ==
-                    MSG_EXT_WDTR_BUS_16_BIT) )
-              {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
-                break;
-              }
-            } /* Fall through if we aren't a wide card */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
               break;
             }
           }
-          if ( (p->transinfo[tindex].goal_period > 9) ||
-               (p->transinfo[tindex].goal_options == 0) )
+          default:
           {
-            scb->flags &= ~SCB_MSGOUT_BITS;
-            reject = TRUE;
-            reply = FALSE;
-            p->needppr &= ~(1 << tindex);
-            p->needppr_copy &= ~(1 << tindex);
-            if ( p->transinfo[tindex].goal_offset )
+            if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                 ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                  (aic7xxx_verbose > 0xffff)) )
             {
-              p->needsdtr |= (1 << tindex);
-              p->needsdtr_copy |= (1 << tindex);
-            }
-            if ( p->transinfo[tindex].goal_width )
-            {
-              p->needwdtr |= (1 << tindex);
-              p->needwdtr_copy |= (1 << tindex);
+              reply = TRUE;
+              printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
             }
+          } /* We fall through on purpose */
+          case MSG_EXT_WDTR_BUS_8_BIT:
+          {
+            /*
+             * According to the spec, if we aren't wide, we also can't be
+             * Dual Edge so clear the options byte
+             */
+            new_trans_options = 0;
+            new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+            break;
           }
         }
+
+        if(reply)
+        {
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
         else
         {
-          switch(bus_width)
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
+
+        /*
+         * As it turns out, if we don't *have* to have PPR messages, then
+         * configure ourselves not to use them since that makes some
+         * external drive chassis work (those chassis can't parse PPR
+         * messages and they mangle the SCSI bus until you send a WDTR
+         * and SDTR that they can understand).
+         */
+        if(new_trans_options == 0)
+        {
+          p->needppr &= ~target_mask;
+          p->needppr_copy &= ~target_mask;
+          if(new_offset)
           {
-            default:
-            {
-              reject = TRUE;
-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
-                    (aic7xxx_verbose > 0xffff)) )
-              {
-                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
-                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-              }
-            } /* We fall through on purpose */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              /*
-               * According to the spec, if we aren't wide, we also can't be
-               * Dual Edge so clear the options byte
-               */
-              new_trans_options = 0;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              break;
-            }
-            case MSG_EXT_WDTR_BUS_16_BIT:
-            {
-              break;
-            }
+            p->needsdtr |= target_mask;
+            p->needsdtr_copy |= target_mask;
+          }
+          if (new_bus_width)
+          {
+            p->needwdtr |= target_mask;
+            p->needwdtr_copy |= target_mask;
           }
         }
 
-        if ( !reject )
+        if((new_offset == 0) && (offset != 0))
         {
-          aic7xxx_set_width(p, target, channel, lun, bus_width,
-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
-                                           &new_trans_options);
-          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, new_trans_options,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          /*
+           * Oops, the syncrate went to low for this card and we fell off
+           * to async (should never happen with a device that uses PPR
+           * messages, but have to be complete)
+           */
+          reply = TRUE;
         }
 
-        p->dtr_pending &= ~target_mask;
-        p->needppr &= ~target_mask;
         if(reply)
         {
-          p->dtr_pending |= target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_PPR;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
+        else
+        {
+          p->needppr &= ~target_mask;
+        }
         done = TRUE;
         break;
       }
@@ -6115,16 +6256,14 @@
         printerror = 0;
       }
     }
-    if ( (scb != NULL) &&
-         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+    if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) 
     {
       /*
-       * This might be a SCSI-3 device that is dropping the bus due to
-       * errors and signalling that we should reduce the transfer speed.
-       * All we have to do is complete this command (since it's a negotiation
-       * command already) and the checksum routine should flag an error and
-       * reduce the speed setting and renegotiate.  We call the reset routing
-       * just to clean out the hardware from this scb.
+       * Hmmm...error during a negotiation command.  Either we have a
+       * borken bus, or the device doesn't like our negotiation message.
+       * Since we check the INQUIRY data of a device before sending it
+       * negotiation messages, assume the bus is borken for whatever
+       * reason.  Complete the command.
        */
       printerror = 0;
       aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
@@ -6256,19 +6395,6 @@
         cmd->result = 0;
         scb = NULL;
       }
-      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
-      {
-        /*
-         * Turn off the needsdtr, needwdtr, and needppr bits since this device
-         * doesn't seem to exist.
-         */
-        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-      }
     }
     /*
      * Keep the sequencer from trying to restart any selections
@@ -6391,7 +6517,6 @@
       }
     }
     else if( (lastphase == P_MESGOUT) &&
-             (cmd == p->dev_dtr_cmnd[tindex]) &&
              (scb->flags & SCB_MSGOUT_PPR) )
     {
       /*
@@ -6410,7 +6535,6 @@
       aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
                            0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
       p->transinfo[tindex].goal_options = 0;
-      p->dtr_pending &= ~(1 << tindex);
       scb->flags &= ~SCB_MSGOUT_BITS;
       if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
       {
@@ -6433,87 +6557,6 @@
       }
       scb = NULL;
     }
-    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
-    {
-      struct aic7xxx_syncrate *syncrate;
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-      /*
-       * oops, we had a failure, lower the transfer rate and try again.  It's
-       * worth noting here that it might be wise to also check for typical
-       * wide setting on narrow cable type problems and try disabling wide
-       * instead of slowing down if those exist.  That's hard to do with simple
-       * checksums though.
-       */
-      printk(WARN_LEAD "Parity error during %s phase.\n",
-             p->host_no, CTL_OF_SCB(scb), phase);
-      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-      {
-        syncrate++;
-        if( (syncrate->rate[0] != NULL) &&
-            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-        {
-          p->transinfo[tindex].goal_period = syncrate->period;
-          if( p->transinfo[tindex].goal_period > 9 )
-          {
-            p->transinfo[tindex].goal_options = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-            if (p->transinfo[tindex].goal_width)
-            {
-              p->needwdtr |= (1<<tindex);
-              p->needwdtr_copy |= (1<<tindex);
-            }
-          }
-        }
-        else if (p->transinfo[tindex].goal_width)
-        {
-          p->transinfo[tindex].goal_width = 0;
-          p->needwdtr &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-          p->transinfo[tindex].goal_offset =
-            p->transinfo[tindex].user_offset;
-          p->transinfo[tindex].goal_period =
-            p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_options =
-            p->transinfo[tindex].user_options;
-          if( p->transinfo[tindex].goal_period <= 9 )
-          {
-            p->needppr |= (1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needppr_copy |= (1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-          }
-          else
-          {
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-          }
-        }
-        else
-        {
-          p->transinfo[tindex].goal_offset = 0;
-          p->transinfo[tindex].goal_period = 255;
-          p->transinfo[tindex].goal_options = 0;
-          p->transinfo[tindex].goal_width = 0;
-          p->needppr &= ~(1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needwdtr &= ~(1<<tindex);
-          p->needppr_copy &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-        }
-      }
-      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
-    }
-    else
-    {
-      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
-    }
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -6782,34 +6825,11 @@
     else if (scb->flags & SCB_SENSE)
     {
       char *buffer = &scb->cmd->sense_buffer[0];
-      if (scb->cmd == p->dev_dtr_cmnd[tindex])
-      {
-        struct aic7xxx_scb *old_scb;
-        /*
-         * We have valid sense data, send it back immediately.
-         */
-        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
-        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
-        old_scb->hscb->target_status = scb->hscb->target_status;
-        old_scb->cmd->result = scb->hscb->target_status;
-        old_scb->cmd->result |= (DID_ERROR << 16);
-        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
-        scbq_remove(&p->waiting_scbs, old_scb);
-        scbq_remove(&p->delayed_scbs[tindex], old_scb);
-        scb->cmd->next = NULL;
-	aic7xxx_done(p, scb);
-        aic7xxx_done(p, old_scb);
-	continue;
-      } 
-      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+
+      if (buffer[12] == 0x47 || buffer[12] == 0x54)
       {
         /*
-         * SCSI errors, run domain validation and re-run negotiation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
+         * Signal that we need to re-negotiate things.
          */
         p->needppr |= (p->needppr_copy & (1<<tindex));
         p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
@@ -6822,7 +6842,18 @@
       case BUSY:
         scb->hscb->target_status = 0;
         scb->cmd->result = 0;
+        scb->hscb->residual_SG_segment_count = 0;
+        scb->hscb->residual_data_count[0] = 0;
+        scb->hscb->residual_data_count[1] = 0;
+        scb->hscb->residual_data_count[2] = 0;
         aic7xxx_error(scb->cmd) = DID_OK;
+        aic7xxx_status(scb->cmd) = 0;
+        /*
+         * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
+         * this command on a timer and allowing us to retry it.  Here, we
+         * just 0 out a few values so that they don't carry through to when
+         * the command finally does complete.
+         */
         break;
       default:
         cmd = scb->cmd;
@@ -6987,18 +7018,14 @@
   if(!p)
     return;
   spin_lock_irqsave(&io_request_lock, cpu_flags);
-  if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
-  {
-    spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-    return;
-  }
+  p->flags |= AHC_IN_ISR;
   do
   {
     aic7xxx_isr(irq, dev_id, regs);
   } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
-  clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
+  p->flags &= ~AHC_IN_ISR;
   spin_unlock_irqrestore(&io_request_lock, cpu_flags);
 }
 
@@ -8779,7 +8806,7 @@
 
   /*
    * In the future, we may call this function as a last resort for
-   * error handling.  Let's be nice and not do any unecessary delays.
+   * error handling.  Let's be nice and not do any unnecessary delays.
    */
   wait = 1000;  /* 1 msec (1000 * 1 msec) */
   while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
@@ -8923,22 +8950,6 @@
     kfree(p->scb_data);
   }
 
-  /*
-   * Free any alloced Scsi_Cmnd structures that might be around for
-   * negotiation purposes....
-   */
-  for (i = 0; i < MAX_TARGETS; i++)
-  {
-    if(p->dev_dtr_cmnd[i])
-    {
-      if(p->dev_dtr_cmnd[i]->request_buffer)
-      {
-        kfree(p->dev_dtr_cmnd[i]->request_buffer);
-      }
-      kfree(p->dev_dtr_cmnd[i]);
-    }
-  }
-
   pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
 }
 
@@ -9325,7 +9336,7 @@
   }
   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
-  p->needppr = p->needppr_copy = p->needdv = 0;
+  p->needppr = p->needppr_copy = 0;
   p->needwdtr = p->needwdtr_copy;
   p->needsdtr = p->needsdtr_copy;
   p->dtr_pending = 0;
@@ -9383,6 +9394,81 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_configure_bugs
+ *
+ * Description:
+ *   Take the card passed in and set the appropriate bug flags based upon
+ *   the card model.  Also make any changes needed to device registers or
+ *   PCI registers while we are here.
+ *-F*************************************************************************/
+static void
+aic7xxx_configure_bugs(struct aic7xxx_host *p)
+{
+  unsigned short tmp_word;
+ 
+  switch(p->chip & AHC_CHIPID_MASK)
+  {
+    case AHC_AIC7860:
+      p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+      /* fall through */
+    case AHC_AIC7850:
+    case AHC_AIC7870:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7880:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7890:
+      p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
+      break;
+    case AHC_AIC7892:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    case AHC_AIC7895:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7896:
+      p->bugs |= AHC_BUG_CACHETHEN_DIS;
+      break;
+    case AHC_AIC7899:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    default:
+      /* Nothing to do */
+      break;
+  }
+
+  /*
+   * Now handle the bugs that require PCI register or card register tweaks
+   */
+  pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
+  if(p->bugs & AHC_BUG_PCI_MWI)
+  {
+    tmp_word &= ~PCI_COMMAND_INVALIDATE;
+  }
+  else
+  {
+    tmp_word |= PCI_COMMAND_INVALIDATE;
+  }
+  pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
+
+  if(p->bugs & AHC_BUG_CACHETHEN)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
+  }
+  else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
+  }
+
+  return;
+}
+
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_detect
  *
  * Description:
@@ -10076,6 +10162,14 @@
             aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
           }
 
+          /*
+           * Call our function to fixup any bugs that exist on this chipset.
+           * This may muck with PCI settings and other device settings, so
+           * make sure it's after all the other PCI and device register
+           * tweaks so it can back out bad settings on specific broken cards.
+           */
+          aic7xxx_configure_bugs(temp_p);
+
           if ( list_p == NULL )
           {
             list_p = current_p = temp_p;
@@ -10319,6 +10413,11 @@
     }
 
     /*
+     * All the 7770 based chipsets have this bug
+     */
+    temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
+
+    /*
      * Set the FIFO threshold and the bus off time.
      */
     hostconf = aic_inb(temp_p, HOSTCONF);
@@ -10537,308 +10636,16 @@
   return (found);
 }
 
-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
-                                           Scsi_Cmnd *old_cmd, int tindex);
-
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_allocate_negotiation_command
+ *   aic7xxx_print_scb
  *
  * Description:
- *   allocate the actual command struct and fill in the gaps...
+ *   Dump the byte codes for an about to be sent SCB.
  *-F*************************************************************************/
-static Scsi_Cmnd *
-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
-                                     Scsi_Cmnd *old_cmd, int tindex)
-{
-  Scsi_Cmnd *cmd;
-  char *buffer;
-
-  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
-  {
-    return(NULL);
-  }
-  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
-  {
-    kfree(p->dev_dtr_cmnd[tindex]);
-    p->dev_dtr_cmnd[tindex] = NULL;
-    return(NULL);
-  }
-  cmd = p->dev_dtr_cmnd[tindex];
-  memset(cmd, 0, sizeof(Scsi_Cmnd));
-  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-  cmd->lun = 0;
-  cmd->request_bufflen = 255;
-  cmd->request_buffer = buffer;
-  cmd->sc_data_direction = SCSI_DATA_READ;
-  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-  cmd->bufflen = 0;
-  cmd->buffer = NULL;
-  cmd->underflow = 0;
-  cmd->cmd_len = 6;
-  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
-  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
-  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
-  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
-  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
-  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
-  return(cmd);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_negotiation_complete
- *
- * Description:
- *   Handle completion events for our Negotiation commands.  Clear out the
- *   struct and get it ready for its next use.
- *-F*************************************************************************/
-static void
-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
-{
-  unsigned int checksum;
-  int i;
-  int *ibuffer;
-  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
-  int tindex = TARGET_INDEX(cmd);
-  struct aic7xxx_syncrate *syncrate;
-
-  /*
-   * perform our minimalistic domain validation
-   */
-  if(p->dev_flags[tindex] & DEVICE_SCANNED)
-  {
-    ibuffer = (int *)cmd->request_buffer;
-    checksum = 0;
-    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
-    {
-      checksum += ibuffer[i];
-    }
-    if( (checksum != p->dev_checksum[tindex]) &&
-        (p->transinfo[tindex].cur_offset != 0) )
-    {
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-
-      if (p->needdv & (1<<tindex))
-      {
-        /*
-         * oops, we had a failure, lower the transfer rate and try again.  It's
-         * worth noting here that it might be wise to also check for typical
-         * wide setting on narrow cable type problems and try disabling wide
-         * instead of slowing down if those exist.  That's hard to do with simple
-         * checksums though.
-         */
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
-                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
-        }
-        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-        {
-          syncrate++;
-          if( (syncrate->rate[0] != NULL) &&
-              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-          {
-            p->transinfo[tindex].goal_period = syncrate->period;
-            if( p->transinfo[tindex].goal_period > 9 )
-            {
-              p->transinfo[tindex].goal_options = 0;
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-              if (p->transinfo[tindex].goal_width)
-              {
-                p->needwdtr |= (1<<tindex);
-                p->needwdtr_copy |= (1<<tindex);
-              }
-            }
-          }
-          else if (p->transinfo[tindex].goal_width)
-          {
-            p->transinfo[tindex].goal_width = 0;
-            p->needwdtr &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
-            if( p->transinfo[tindex].goal_period <= 9 )
-            {
-              p->needppr |= (1<<tindex);
-              p->needsdtr &= ~(1<<tindex);
-              p->needppr_copy |= (1<<tindex);
-              p->needsdtr_copy &= ~(1<<tindex);
-            }
-            else
-            {
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-            }
-          }
-          else
-          {
-            p->transinfo[tindex].goal_offset = 0;
-            p->transinfo[tindex].goal_period = 255;
-            p->transinfo[tindex].goal_options = 0;
-            p->transinfo[tindex].goal_width = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needwdtr &= ~(1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-          }
-        }
-        p->needdv &= ~(1<<tindex);
-      }
-      else
-      {
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "Performing Domain validation.\n",
-                 p->host_no, CTL_OF_CMD(cmd));
-        }
-        /*
-         * Update the checksum in case the INQUIRY data has changed, maybe
-         * in relation to a change in the mode pages, or whatever.
-         */
-        p->dev_checksum[tindex] = checksum;
-        /*
-         * Signal that we are trying out the domain validation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
-         */
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
-      }
-    } 
-    else
-    {
-      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-          (p->needdv & (1<<tindex)) )
-      {
-        printk(INFO_LEAD "Successfully completed Domain validation.\n",
-               p->host_no, CTL_OF_CMD(cmd));
-      }
-      /*
-       * We successfully did our checksum, so don't leave the needdv flag set
-       * in case we might have set it last time through.
-       */
-      p->needdv &= ~(1<<tindex);
-    }
-  }
-
-  p->dtr_pending &= ~(0x01 << tindex);
-  /*
-   * This looks recursive in the extreme, but if this was a WDTR negotiation
-   * and we didn't follow up with SDTR yet, then this will get it started.
-   * For all other cases, this should work out to be a no-op, unless we are
-   * doing domain validation and happen to need a new negotiation command.
-   *
-   * In case we don't want this to go any further, the cmdcmplt interrupt
-   * handler will NULL out the cmd->next entry so that the real SCSI command
-   * can be sent back to the mid layer code with SENSE data intact.  We'll
-   * finish things up when the cmd gets sent back down to us, so no worries.
-   */
-  if(cmd->next)
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
-  }
-  return;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_build_negotiation_command
- *
- * Description:
- *   Build a Scsi_Cmnd structure to perform negotiation with or else send
- *   a pre-built command specifically for this purpose.
- *-F*************************************************************************/
-static void
-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
-  int tindex)
-{
-
-  if ( !(p->dtr_pending & (1<<tindex)) &&
-       ( (p->needppr & (1<<tindex)) ||
-         (p->needwdtr & (1<<tindex)) ||
-         (p->needsdtr & (1<<tindex)) ) )
-  {
-    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
-         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
-    {
-      return;
-    }
-    /*
-     * Before sending this thing out, we also make the cmd->next pointer
-     * point to the real command so we can stuff any possible SENSE data
-     * into the real command instead of this fake command.  This has to be
-     * done each time the command is built, not just the first time, hence
-     * it's outside of the above if()...
-     */
-    p->dev_dtr_cmnd[tindex]->next = old_cmd;
-    /*
-     * Clear the buffer so checksums come out right....
-     */
-    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
-           p->dev_dtr_cmnd[tindex]->request_bufflen);
-    /*
-     * Remove any commands for this particular device that might be on the
-     * waiting_scbs queue or qinfifo so that this command goes out first.
-     * This is vital for our implementation of domain validation.
-     */
-    pause_sequencer(p);
-    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
-                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
-    unpause_sequencer(p, FALSE);
-    {
-      struct aic7xxx_scb *scb, *next;
-
-      scb = p->waiting_scbs.head;
-      while(scb != NULL)
-      {
-        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
-                              ALL_LUNS, SCB_LIST_NULL) )
-        {
-          next = scb->q_next;
-          scbq_remove(&p->waiting_scbs, scb);
-          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-          scb = next;
-        }
-        else
-        {
-          scb = scb->q_next;
-        }
-      }
-    }
-    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
-                  aic7xxx_negotiation_complete);
-  }
-}
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_print_scb
- *
- * Description:
- *   Dump the byte codes for an about to be sent SCB.
- *-F*************************************************************************/
-static void
-aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+static void
+aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   int i;
   unsigned char *x;  
@@ -10877,7 +10684,7 @@
    */
   hscb->control = 0;
   scb->tag_action = 0;
-  cmd->tag = hscb->tag;
+
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
@@ -10906,34 +10713,29 @@
       }
     }
   }
-  if ( cmd == p->dev_dtr_cmnd[tindex] )
+  if ( !(p->dtr_pending & mask) &&
+        ( (p->needppr & mask) ||
+          (p->needwdtr & mask) ||
+          (p->needsdtr & mask) ) &&
+        (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
   {
     p->dtr_pending |= mask;
     scb->tag_action = 0;
-    if (p->dev_flags[tindex] & DEVICE_SCANNED)
+    hscb->control &= DISCENB;
+    hscb->control |= MK_MESSAGE;
+    if(p->needppr & mask)
     {
-      hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
-      if(p->needppr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_PPR;
-      }
-      else if(p->needwdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_WDTR;
-      }
-      else if(p->needsdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_SDTR;
-      }
+      scb->flags |= SCB_MSGOUT_PPR;
     }
-  }
-  if ( !(p->dtr_pending & mask) &&
-        ( (p->needppr & mask) ||
-          (p->needwdtr & mask) ||
-          (p->needsdtr & mask) ) )
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
+    else if(p->needwdtr & mask)
+    {
+      scb->flags |= SCB_MSGOUT_WDTR;
+    }
+    else if(p->needsdtr & mask)
+    {
+      scb->flags |= SCB_MSGOUT_SDTR;
+    }
+    scb->flags |= SCB_DTR_SCB;
   }
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -11079,50 +10881,58 @@
     aic7xxx_allocate_scb(p);
     DRIVER_UNLOCK
     scb = scbq_remove_head(&p->scb_data->free_scbs);
-  }
-  if (scb == NULL)
-  {
-    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
-           CTL_OF_CMD(cmd));
-    cmd->result = (DID_BUS_BUSY << 16);
+    if(scb == NULL)
+      printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+             CTL_OF_CMD(cmd));
+  }
+  while (scb == NULL)
+  {
+    /*
+     * Well, all SCBs are currently active on the bus.  So, we spin here
+     * running the interrupt handler until one completes and becomes free.
+     * We can do this safely because we either A) hold the driver lock (in
+     * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
+     * kernels) and so either way, we won't take any other interrupts and
+     * the queue path will block until we release it.  Also, we would worry
+     * about running the completion queues, but obviously there are plenty
+     * of commands outstanding to trigger a later interrupt that will do
+     * that for us, so skip it here.
+     */
     DRIVER_LOCK
-    aic7xxx_queue_cmd_complete(p, cmd);
+    aic7xxx_isr(p->irq, p, NULL);
     DRIVER_UNLOCK
-    return 0;
+    scb = scbq_remove_head(&p->scb_data->free_scbs);
   }
-  else
-  {
-    scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->hscb->tag;
+  scb->cmd = cmd;
+  aic7xxx_position(cmd) = scb->hscb->tag;
 
-    /*
-     * Construct the SCB beforehand, so the sequencer is
-     * paused a minimal amount of time.
-     */
-    aic7xxx_buildscb(p, cmd, scb);
+  /*
+   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+   * is set up properly, and the parity error flag is reset, then send
+   * the SCB to the sequencer and watch the fun begin.
+   */
+  cmd->scsi_done = fn;
+  cmd->result = DID_OK;
+  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+  aic7xxx_error(cmd) = DID_OK;
+  aic7xxx_status(cmd) = 0;
+  cmd->host_scribble = NULL;
 
-    /*
-     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
-     * is set up properly, and the parity error flag is reset, then send
-     * the SCB to the sequencer and watch the fun begin.
-     */
-    cmd->scsi_done = fn;
-    cmd->result = DID_OK;
-    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-    aic7xxx_error(cmd) = DID_OK;
-    aic7xxx_status(cmd) = 0;
-    cmd->host_scribble = NULL;
+  /*
+   * Construct the SCB beforehand, so the sequencer is
+   * paused a minimal amount of time.
+   */
+  aic7xxx_buildscb(p, cmd, scb);
 
-    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+  scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    DRIVER_LOCK
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
-    {
-      aic7xxx_run_waiting_queues(p);
-    }
-    DRIVER_UNLOCK
+  DRIVER_LOCK
+  scbq_insert_tail(&p->waiting_scbs, scb);
+  if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+  {
+    aic7xxx_run_waiting_queues(p);
   }
+  DRIVER_UNLOCK
   return (0);
 }
 
@@ -11188,6 +10998,12 @@
          aic_inb(p, SCSISIGI),
          aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
          aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
+         CTL_OF_SCB(scb),
+         (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SSTAT2),
+         aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
+         aic_inb(p, STCNT));
   }
 
   channel = cmd->channel;
@@ -11358,7 +11174,6 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned long cpu_flags = 0;
 #endif
-  Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
@@ -11367,7 +11182,7 @@
    * I added a new config option to the driver: "panic_on_abort" that will
    * cause the driver to panic and the machine to stop on the first abort
    * or reset call into the driver.  At that point, it prints out a lot of
-   * usefull information for me which I can then use to try and debug the
+   * useful information for me which I can then use to try and debug the
    * problem.  Simply enable the boot time prompt in order to activate this
    * code.
    */
@@ -11388,13 +11203,11 @@
   {
     aic7xxx_isr(p->irq, p, (void *)NULL);
     pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
   }
+  aic7xxx_done_cmds_complete(p);
 
-  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
-                      /*  Totally bogus cmd since it points beyond our  */
-  {                   /*  valid SCB range or doesn't even match it's own*/
-                      /*  timeout serial number.                        */
+  if (scb == NULL)
+  {
     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
       printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
         "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11413,28 +11226,6 @@
                         /*  finish successfully, or to indicate that we     */
                         /*  don't have this cmd any more and the mid level  */
                         /*  code needs to find it.                          */
-    cmd_next = p->completeq.head;
-    cmd_prev = NULL;
-    while (cmd_next != NULL) 
-    {
-      if (cmd_next == cmd) 
-      {
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "Abort called for command "
-          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        if ( cmd_prev == NULL )
-          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-        else
-          cmd_prev->host_scribble = cmd_next->host_scribble;
-        cmd_next->scsi_done(cmd_next);
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
-                                         * completion */
-      }                                  
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
       printk(INFO_LEAD "Abort called for already completed"
         " command.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11492,8 +11283,20 @@
   found = 0;
   p->flags |= AHC_IN_ABORT;
   if (aic7xxx_verbose & VERBOSE_ABORT)
-    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
-         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  {
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
+         aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
+         aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
 
 /*
  *   First, let's check to see if the currently running command is our target
@@ -11521,6 +11324,16 @@
         if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
           printk(INFO_LEAD "SCB is currently active.  "
                 "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb),
+           (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
         unpause_sequencer(p, FALSE);
         p->flags &= ~AHC_IN_ABORT;
         scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
@@ -11536,35 +11349,7 @@
   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
     int tindex = TARGET_INDEX(cmd);
-    unsigned short mask;
-
-    mask = (1 << tindex);
 
-    if (p->dtr_pending & mask)
-    {
-      if (p->dev_dtr_cmnd[tindex]->next != cmd)
-        found = 1;
-      else
-        found = 0;
-    }
-    else
-    {
-      found = 1;
-    }
-    if (found == 0)
-    {
-      /*
-       * OK..this means the command we are currently getting an abort
-       * for has an outstanding negotiation command in front of it.
-       * We don't really have a way to tie back into the negotiation
-       * commands, so we just send this back as pending, then it
-       * will get reset in 2 seconds.
-       */
-      unpause_sequencer(p, TRUE);
-      scb->flags |= SCB_ABORT;
-      DRIVER_UNLOCK
-      return(SCSI_ABORT_PENDING);
-    }
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
       printk(INFO_LEAD "SCB found on waiting list and "
           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -11721,10 +11506,8 @@
 #define DEVICE_RESET 0x01
 #define BUS_RESET    0x02
 #define HOST_RESET   0x04
-#define FAIL         0x08
-#define RESET_DELAY  0x10
+#define RESET_DELAY  0x08
   int        action;
-  Scsi_Cmnd *cmd_prev, *cmd_next;
 
 
   if ( cmd == NULL )
@@ -11742,7 +11525,7 @@
    * I added a new config option to the driver: "panic_on_abort" that will
    * cause the driver to panic and the machine to stop on the first abort
    * or reset call into the driver.  At that point, it prints out a lot of
-   * usefull information for me which I can then use to try and debug the
+   * useful information for me which I can then use to try and debug the
    * problem.  Simply enable the boot time prompt in order to activate this
    * code.
    */
@@ -11752,86 +11535,32 @@
   DRIVER_LOCK
 
   pause_sequencer(p);
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
-  {
-    aic7xxx_isr(p->irq, p, (void *)NULL );
-    pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
-  }
 
-  if (scb == NULL)
+  if(flags & SCSI_RESET_SYNCHRONOUS)
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
-           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
-    {
-      action = HOST_RESET;
-    }
-    else
-    {
-      action = BUS_RESET;
-    }
+      printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
+           "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
+           cmd->result);
+    scb = NULL;
+    action = HOST_RESET;
   }
-  else if (scb->cmd != cmd) 
+  else if ((scb == NULL) || (scb->cmd != cmd))
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
-    printk(INFO_LEAD "Reset called with recycled SCB "
-        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
-    cmd_prev = NULL;
-    cmd_next = p->completeq.head;
-    while ( cmd_next != NULL )
-    {
-      if (cmd_next == cmd)
-      {
-        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-          printk(INFO_LEAD "Reset, found cmd on completeq"
-          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_RESET_NOT_RUNNING);
-      }
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
-    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "Reset, cmd not found,"
-          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_NOT_RUNNING);
-    }
-    else
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_MID)
-        printk(INFO_LEAD "Reset called, no scb, "
-          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
-      scb = NULL;
-      action = HOST_RESET;
-    }
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
+    aic7xxx_done_cmds_complete(p);
+    aic7xxx_run_waiting_queues(p);
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_NOT_RUNNING);
   }
   else
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
       printk(INFO_LEAD "Reset called, scb %d, flags "
         "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
-    {
-      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
-          CTL_OF_SCB(scb));
-      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
-        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
-          CTL_OF_SCB(scb));
-      aic7xxx_handle_command_completion_intr(p);
-      aic7xxx_done_cmds_complete(p);
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_SUCCESS);
-    }
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -11845,6 +11574,26 @@
       action = DEVICE_RESET;
     }
   }
+
+  while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+  {
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
+  }
+  aic7xxx_done_cmds_complete(p);
+
+  if(scb && (scb->cmd == NULL))
+  {
+    /*
+     * We just completed the command when we ran the isr stuff, so we no
+     * longer have it.
+     */
+    aic7xxx_run_waiting_queues(p);
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_SUCCESS);
+  }
+    
   if ( (action & DEVICE_RESET) && 
         (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
   {
@@ -11904,14 +11653,13 @@
   switch (action)
   {
     case RESET_DELAY:
+      aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(SCSI_RESET_PENDING);
-      break;
-    case FAIL:
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_ERROR);
+      if(scb == NULL)
+        return(SCSI_RESET_PUNT);
+      else
+        return(SCSI_RESET_PENDING);
       break;
     case DEVICE_RESET:
       p->flags |= AHC_IN_RESET;
@@ -11929,7 +11677,7 @@
     case HOST_RESET:
     default:
       p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
-      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+      p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
       p->dev_timer_active |= (0x01 << p->scsi_id);
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
@@ -11956,21 +11704,14 @@
         p->msg_index = 0;
         p->msg_len = 0;
       }
-      aic7xxx_run_done_queue(p, TRUE);
-      /*
-       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
-       * in need of being re-started, so send it on through to aic7xxx_queue
-       * and let it set until the delay is over.  This keeps it from dying
-       * entirely and avoids getting a bogus dead command back through the
-       * mid-level code due to too many retries.
-       */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
-      if ( flags & SCSI_RESET_SYNCHRONOUS )
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+      if(flags & SCSI_RESET_SYNCHRONOUS)
       {
-        cmd->result = DID_BUS_BUSY << 16;
+        cmd->result = DID_RESET << 16;
         cmd->done(cmd);
       }
 #endif
+      aic7xxx_run_done_queue(p, TRUE);
       p->flags &= ~AHC_IN_RESET;
       /*
        * We can't rely on run_waiting_queues to unpause the sequencer for
@@ -11981,7 +11722,10 @@
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(result);
+      if(scb == NULL)
+        return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
+      else
+        return(result);
       break;
   }
 }
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/dec_esp.c linux/drivers/scsi/dec_esp.c
--- v2.4.6/linux/drivers/scsi/dec_esp.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/dec_esp.c	Thu Jul  5 11:28:16 2001
@@ -87,7 +87,7 @@
 unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD];
 unsigned char scsi_cur_buff = 1;	/* Leave space for command buffer */
 __u32 esp_virt_buffer;
-int scsi_current_length = 0;
+int scsi_current_length;
 
 volatile unsigned char cmd_buffer[16];
 volatile unsigned char pmaz_cmd_buffer[16];
@@ -181,10 +181,13 @@
 		esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer);
 	
 		esp->irq = SCSI_INT;
-	request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI",
-	            NULL);
-		request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA",
-			    NULL);
+		if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
+				"NCR 53C94 SCSI", NULL))
+			goto err_dealloc;
+		if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, 
+				"JUNKIO SCSI DMA", NULL))
+			goto err_free_irq;
+			
 
 	esp->scsi_id = 7;
 		
@@ -257,7 +260,12 @@
 			esp->dma_mmu_release_scsi_sgl = 0;
 			esp->dma_advance_sg = 0;
 
-			request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ_AA", NULL);
+			if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
+					 "PMAZ_AA", NULL)) {
+				esp_deallocate(esp);
+				release_tc_card(slot);
+				continue;
+			}
 			esp->scsi_id = 7;
 			esp->diff = 0;
 			esp_initialize(esp);
@@ -267,10 +275,16 @@
 
 	if(nesps) {
 		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
-	esps_running = esps_in_use;
-	return esps_in_use;
-	} else
-    return 0;
+		esps_running = esps_in_use;
+		return esps_in_use;
+	}
+	return 0;
+
+ err_free_irq:
+	free_irq(esp->irq, esp_intr);
+ err_dealloc:
+	esp_deallocate(esp);
+	return 0;
 }
 
 /************************************************************* DMA Functions */
@@ -524,4 +538,4 @@
 	    (char *) KSEG0ADDR((sp->request_buffer));
 }
 
-#endif
\ No newline at end of file
+#endif
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.4.6/linux/drivers/scsi/hosts.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/hosts.c	Thu Jul  5 11:28:17 2001
@@ -69,7 +69,7 @@
  *  idiocy.
  */
 
-Scsi_Host_Template * scsi_hosts = NULL;
+Scsi_Host_Template * scsi_hosts;
 
 
 /*
@@ -77,12 +77,12 @@
  *      MAX_SCSI_HOSTS here.
  */
 
-Scsi_Host_Name * scsi_host_no_list = NULL;
-struct Scsi_Host * scsi_hostlist = NULL;
-struct Scsi_Device_Template * scsi_devicelist = NULL;
+Scsi_Host_Name * scsi_host_no_list;
+struct Scsi_Host * scsi_hostlist;
+struct Scsi_Device_Template * scsi_devicelist;
 
-int max_scsi_hosts = 0;
-int next_scsi_host = 0;
+int max_scsi_hosts;
+int next_scsi_host;
 
 void
 scsi_unregister(struct Scsi_Host * sh){
@@ -237,6 +237,7 @@
     retval->use_clustering = tpnt->use_clustering;   
 
     retval->select_queue_depths = tpnt->select_queue_depths;
+    retval->max_sectors = tpnt->max_sectors;
 
     if(!scsi_hostlist)
 	scsi_hostlist = retval;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.4.6/linux/drivers/scsi/hosts.h	Fri May 25 18:02:21 2001
+++ linux/drivers/scsi/hosts.h	Mon Jul  9 11:42:13 2001
@@ -243,6 +243,11 @@
     short unsigned int sg_tablesize;
 
     /*
+     * if the host adapter has limitations beside segment count
+     */
+    short unsigned int max_sectors;
+
+    /*
      * True if this host adapter can make good use of linked commands.
      * This will allow more than one command to be queued to a given
      * unit on a given host.  Set this to the maximum number of command
@@ -380,6 +385,7 @@
     int can_queue;
     short cmd_per_lun;
     short unsigned int sg_tablesize;
+    short unsigned int max_sectors;
 
     unsigned in_recovery:1;
     unsigned unchecked_isa_dma:1;
@@ -523,7 +529,7 @@
 
 /* These are used by loadable modules */
 extern int scsi_register_module(int, void *);
-extern void scsi_unregister_module(int, void *);
+extern int scsi_unregister_module(int, void *);
 
 /* The different types of modules that we can load and unload */
 #define MODULE_SCSI_HA 1
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.4.6/linux/drivers/scsi/megaraid.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/megaraid.c	Wed Jul  4 11:50:39 2001
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : v1.14g (Feb 5, 2001)
+ * Version : v1.15d(May 30, 2001)
  *
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -296,6 +296,63 @@
  *	Version 1.14g-ac2 - 22/03/01
  *	Fixed a non obvious dereference after free in the driver unload path
  *
+ *	Version 1.14i
+ *	changes for making 32bit application run on IA64
+ *
+ *	Version 1.14j
+ *	Tue Mar 13 14:27:54 EST 2001 - AM
+ *	Changes made in the driver to be able to run applications if the
+ *	system has memory >4GB.
+ *
+ *
+ *	Version 1.14k
+ *	Thu Mar 15 18:38:11 EST 2001 - AM
+ *
+ *	Firmware version check removed if subsysid==0x1111 and
+ *	subsysvid==0x1111, since its not yet initialized.
+ *
+ *	changes made to correctly calculate the base in mega_findCard.
+ *
+ *	Driver informational messages now appear on the console as well as
+ *	with dmesg
+ *
+ *	Older ioctl interface is returned failure on newer(2.4.xx) kernels.
+ *
+ *	Inclusion of "modversions.h" is still a debatable question. It is
+ *	included anyway with this release.
+ *
+ *	Version 1.14l
+ *	Mon Mar 19 17:39:46 EST 2001 - AM
+ *
+ *	Assorted changes to remove compilation error in 1.14k when compiled
+ *	with kernel < 2.4.0
+ *
+ *	Version 1.15
+ *	Thu Apr 19 09:38:38 EDT 2001 - AM
+ *
+ *	1.14l rollover to 1.15
+ *
+ *	Version 1.15b
+ *  Wed May 16 20:10:01 EDT 2001 - AM
+ *
+ *	"modeversions.h" is no longer included in the code.
+ *	2.4.xx style mutex initialization used for older kernels also
+ *	Brought in-sync with Alan's changes in 2.4.4
+ *	Note: 1.15a is on OBDR brabch(main trunk), and is not merged with yet.
+ *
+ * Version 1.15c
+ * Mon May 21 23:10:42 EDT 2001 - AM
+ *
+ * ioctl interface uses 2.4.x conforming pci dma calls
+ * similar calls used for older kernels
+ *
+ * Version 1.15d
+ * Wed May 30 17:30:41 EDT 2001 - AM
+ *
+ * NULL is not a valid first argument for pci_alloc_consistent() on
+ * IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get
+ * "pci_dev" before making calls to pci interface routines.
+
  * 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.
@@ -399,7 +456,11 @@
 #define cpuid smp_processor_id()
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+#define scsi_set_pci_device(x,y)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
 
 /*
  *	Linux 2.4 and higher
@@ -447,10 +508,12 @@
 #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
 
 #define pci_free_consistent(a,b,c,d)
-#define pci_unmap_single(a,b,c,d,e)
+#define pci_unmap_single(a,b,c,d)
+
+#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x)           (*(x)=MUTEX)
 
-#define init_MUTEX_LOCKED(x)	((x)=MUTEX_LOCKED)
-#define init_MUTEX(x)		((x)=MUTEX)
+#define pci_enable_device(x) (0)
 
 #define queue_task_irq(a,b)     queue_task(a,b)
 #define queue_task_irq_off(a,b) queue_task(a,b)
@@ -480,10 +543,12 @@
 #define cpu_to_le32(x) (x)
 
 #define pci_free_consistent(a,b,c,d)
-#define pci_unmap_single(a,b,c,d,e)
+#define pci_unmap_single(a,b,c,d)
+
+#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x)           (*(x)=MUTEX)
 
-#define init_MUTEX_LOCKED(x)	((x)=MUTEX_LOCKED)
-#define init_MUTEX(x)		((x)=MUTEX)
+#define pci_enable_device(x) (0)
 
 /*
  *	2.0 lacks spinlocks, iounmap/ioremap
@@ -508,6 +573,16 @@
 #endif
 
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
+#define dma_alloc_consistent pci_alloc_consistent
+#define dma_free_consistent pci_free_consistent
+#else
+typedef unsigned long dma_addr_t;
+void *dma_alloc_consistent(void *, size_t, dma_addr_t *);
+void dma_free_consistent(void *, size_t, void *, dma_addr_t);
+int mega_get_order(int);
+int pow_2(int);
+#endif
 
 /* set SERDEBUG to 1 to enable serial debugging */
 #define SERDEBUG 0
@@ -973,10 +1048,16 @@
 	if ((SCpnt->cmnd[0] == MEGADEVIOC))
 		return megadev_doioctl (megaCfg, SCpnt);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 	if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD)
-	    || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW))
+		    || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)  
 		return mega_ioctl (megaCfg, SCpnt);	/* Handle IOCTL command */
+#else
+	{
+		printk(KERN_WARNING "megaraid ioctl: older interface - "
+				"not supported.\n");
+		return NULL;
+	}
 #endif
 
 	islogical = (SCpnt->channel == megaCfg->host->max_channel);
@@ -1407,7 +1488,7 @@
 		 *   cmnd[4..7] = external user buffer     *
 		 *   cmnd[8..11] = length of buffer        *
 		 *                                         */
-		char *user_area = *((char **) &SCpnt->cmnd[4]);
+      	char *user_area = (char *)*((u32*)&SCpnt->cmnd[4]);
 		u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]);
 		switch (data[0]) {
 		case FW_FIRE_WRITE:
@@ -1598,8 +1679,8 @@
 	mbox->xferaddr = virt_to_bus (pScb->sgList);
 	mbox->numsgelements = idx;
 }
+#endif
 
-#endif				/* KERNEL_VERSION(2,3,0) */
 
 #if DEBUG
 static unsigned int cum_time = 0;
@@ -2348,7 +2429,7 @@
 	megaCfg->biosVer[4] = 0;
 #endif
 
-	printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
+	printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
 		megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
 	/*
 	 * I hope that I can unmap here, reason DMA transaction is not required any more
@@ -2368,7 +2449,7 @@
  * Returns data to be displayed in /proc/scsi/megaraid/X
  *----------------------------------------------------------*/
 
-static int megaraid_proc_info (char *buffer, char **start, off_t offset,
+int megaraid_proc_info (char *buffer, char **start, off_t offset,
 		    int length, int host_no, int inout)
 {
 	*start = buffer;
@@ -2411,7 +2492,7 @@
 #endif
 
 	while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
-		if (pci_enable_device (pdev))
+		if(pci_enable_device (pdev))
 			continue;
 		pciBus = pdev->bus->number;
 		pciDevFun = pdev->devfn;
@@ -2425,11 +2506,16 @@
 				continue;	/* not an AMI board */
 			}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if 0
+/*
+ *	This leads to corruption on some HP boards so disable it
+ */
 			pcibios_read_config_dword (pciBus, pciDevFun,
 						   PCI_CONF_AMISIG64, &magic64);
 
 			if (magic64 == AMI_64BIT_SIGNATURE)
 				flag |= BOARD_64BIT;
+#endif				
 #endif
 		}
 
@@ -2451,9 +2537,7 @@
 			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"))) {
+			if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
 				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"
@@ -2476,7 +2560,7 @@
 				continue;
 		}
 
-		printk (KERN_INFO
+		printk (KERN_NOTICE
 			"megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
 			pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun),
 			PCI_FUNC (pciDevFun));
@@ -2499,11 +2583,14 @@
 		pciIdx++;
 
 		if (flag & BOARD_QUARTZ) {
+			megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
 			megaBase = (long) ioremap (megaBase, 128);
 			if (!megaBase)
 				continue;
-		} else
+		} else {
+			megaBase &= PCI_BASE_ADDRESS_IO_MASK;
 			megaBase += 0x10;
+		}
 
 		/* Initialize SCSI Host structure */
 		host = scsi_register (pHostTmpl, sizeof (mega_host_config));
@@ -2514,11 +2601,11 @@
 		megaCfg = (mega_host_config *) host->hostdata;
 		memset (megaCfg, 0, sizeof (mega_host_config));
 
-		printk (KERN_INFO "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d"
+		printk (KERN_NOTICE "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d"
 			M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq);
 
 		if (flag & BOARD_64BIT)
-			printk (KERN_INFO "scsi%d : Enabling 64 bit support\n",
+			printk (KERN_NOTICE "scsi%d : Enabling 64 bit support\n",
 				host->host_no);
 
 		/* Copy resource info into structure */
@@ -2549,10 +2636,11 @@
 
 		if (!(flag & BOARD_QUARTZ)) {
 			/* Request our IO Range */
-			if (!request_region(megaBase, 16, "megaraid")) {
-				printk (KERN_WARNING "megaraid: Couldn't register I/O range!" M_RD_CRLFSTR);
+			if (check_region (megaBase, 16)) {
+				printk(KERN_WARNING "megaraid: Couldn't register I/O range!\n");
 				goto err_unregister;
 			}
+			request_region(megaBase, 16, "megaraid");
 		}
 
 		/* Request our IRQ */
@@ -2678,7 +2766,7 @@
 		skip_id = (skip_id > 15) ? -1 : skip_id;
 	}
 
-	printk (KERN_INFO "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR);
+	printk (KERN_NOTICE "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR);
 
 	memset (mega_hbas, 0, sizeof (mega_hbas));
 
@@ -2736,7 +2824,7 @@
 /*---------------------------------------------------------------------
  * Release the controller's resources
  *---------------------------------------------------------------------*/
-static int megaraid_release (struct Scsi_Host *pSHost)
+int megaraid_release (struct Scsi_Host *pSHost)
 {
 	mega_host_config *megaCfg;
 	mega_mailbox *mbox;
@@ -3022,7 +3110,7 @@
 /*----------------------------------------------
  * Get information about the card/driver
  *----------------------------------------------*/
-static const char *megaraid_info (struct Scsi_Host *pSHost)
+const char *megaraid_info (struct Scsi_Host *pSHost)
 {
 	static char buffer[512];
 	mega_host_config *megaCfg;
@@ -3052,7 +3140,7 @@
  *   10 01 numstatus byte
  *   11 01 status byte
  *-----------------------------------------------------------------*/
-static int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
+int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
 {
 	DRIVER_LOCK_T mega_host_config * megaCfg;
 	mega_scb *pScb;
@@ -3063,11 +3151,11 @@
 
 	if (!(megaCfg->flag & (1L << SCpnt->channel))) {
 		if (SCpnt->channel < SCpnt->host->max_channel)
-			printk ( /*KERN_INFO */
+			printk ( KERN_NOTICE
 				"scsi%d: scanning channel %c for devices.\n",
 				megaCfg->host->host_no, SCpnt->channel + '1');
 		else
-			printk ( /*KERN_INFO */
+			printk ( KERN_NOTICE
 				"scsi%d: scanning virtual channel for logical drives.\n",
 				megaCfg->host->host_no);
 
@@ -3136,7 +3224,7 @@
 			init_MUTEX_LOCKED (&pScb->ioctl_sem);
 			spin_unlock_irq (&io_request_lock);
 			down (&pScb->ioctl_sem);
-			user_area = *((char **) &pScb->SCpnt->cmnd[4]);
+    		user_area = (char *)*((u32*)&pScb->SCpnt->cmnd[4]);
 			if (copy_to_user
 			    (user_area, pScb->buff_ptr, pScb->iDataSize)) {
 				printk
@@ -3178,7 +3266,7 @@
 
 /* shouldn't be used, but included for completeness */
 
-static int megaraid_command (Scsi_Cmnd * SCpnt)
+int megaraid_command (Scsi_Cmnd * SCpnt)
 {
 	internal_done_flag = 0;
 
@@ -3195,7 +3283,7 @@
 /*---------------------------------------------------------------------
  * Abort a previous SCSI request
  *---------------------------------------------------------------------*/
-static int megaraid_abort (Scsi_Cmnd * SCpnt)
+int megaraid_abort (Scsi_Cmnd * SCpnt)
 {
 	mega_host_config *megaCfg;
 	int rc;			/*, idx; */
@@ -3293,7 +3381,7 @@
  * Reset a previous SCSI request
  *---------------------------------------------------------------------*/
 
-static int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
+int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
 {
 	mega_host_config *megaCfg;
 	int idx;
@@ -3404,7 +3492,7 @@
 	*start = page;
 
 	proc_printf (megaCfg, "Statistical Information for this controller\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
 	proc_printf (megaCfg, "Interrupts Collected = %Lu\n",
 		     megaCfg->nInterrupts);
 #else
@@ -3574,7 +3662,7 @@
  *     geom[1] = sectors
  *     geom[2] = cylinders
  *-------------------------------------------------------------*/
-static int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
+int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
 {
 	int heads, sectors, cylinders;
 	mega_host_config *megaCfg;
@@ -3788,11 +3876,9 @@
 	kdev_t dev;
 	u32 inlen;
 	struct uioctl_t ioc;
-	char *kphysaddr = NULL;
+	char *kvaddr = NULL;
 	int nadap = numCtlrs;
-	int npages;
 	u8 opcode;
-	int order = 0;
 	u32 outlen;
 	int ret;
 	u8 subopcode;
@@ -3800,6 +3886,15 @@
 	struct Scsi_Host *shpnt;
 	char *uaddr;
 	struct uioctl_t *uioc;
+	dma_addr_t	dma_addr;
+	u32		length;
+	mega_host_config *megacfg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
+	struct pci_dev pdev;
+	struct pci_dev *pdevp = &pdev;
+#else
+	char *pdevp = NULL;
+#endif
 	IO_LOCK_T;
 
 	if (!inode || !(dev = inode->i_rdev))
@@ -3809,12 +3904,6 @@
 		return (-EINVAL);
 
 	/*
-	 * We do not transfer more than IOCTL_MAX_DATALEN (see megaraid.h) with
-	 * this interface.If the user needs to transfer more than this,he should
-	 * use 0x81 command op-code.
-	 */
-
-	/*
 	 * Get the user ioctl structure
 	 */
 	ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t));
@@ -3826,10 +3915,10 @@
 		return -EFAULT;
 
 	/*
-	 * The first call the applications should make is to find out the number
-	 * of controllers in the system. The next logical call should be for
-	 * getting the list of controllers in the system as detected by the
-	 * driver.
+	 * The first call the applications should make is to find out the
+	 * number of controllers in the system. The next logical call should
+	 * be for getting the list of controllers in the system as detected
+	 * by the driver.
 	 */
 
 	/*
@@ -3892,173 +3981,135 @@
 		adapno = ioc.ui.fcs.adapno;
 
 		/* See comment above: MEGAIOC_QADAPINFO */
-		adapno = GETADAP (adapno);
+		adapno = GETADAP(adapno);
 
 		if (adapno >= numCtlrs)
-			return (-ENODEV);
+			return(-ENODEV);
 
-		/* Check for zero length buffer. */
-		if (!ioc.ui.fcs.length)
+		length = ioc.ui.fcs.length;
+
+		/* Check for zero length buffer or very large buffers */
+		if( !length || length > 32*1024 )
 			return -EINVAL;
 
 		/* save the user address */
 		uaddr = ioc.ui.fcs.buffer;
 
-/*
-* For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of uioctl_t
-* structure are treated as flags. If outlen is 1, the data is
-* transferred from the device and if inlen is 1, the data is
-* transferred to the device.
-*/
+		/*
+		 * For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of
+		 * uioctl_t structure are treated as flags. If outlen is 1, the
+		 * data is transferred from the device and if inlen is 1, the data
+		 * is transferred to the device.
+		 */
 		outlen = ioc.outlen;
 		inlen = ioc.inlen;
-#if 0
-		if (inlen && outlen)
-			return -EINVAL;
-#endif
-		if (outlen) {
-			ret = verify_area (VERIFY_WRITE,
-					   (char *) ioc.ui.fcs.buffer,
-					   ioc.ui.fcs.length);
-			if (ret)
-				return ret;
-		} else if (inlen) {
-			ret = verify_area (VERIFY_READ,
-					   (char *) ioc.ui.fcs.buffer,
-					   ioc.ui.fcs.length);
 
-			if (ret)
-				return ret;
+		if(outlen) {
+			ret = verify_area(VERIFY_WRITE, (char *)ioc.ui.fcs.buffer, length);
+			if (ret) return ret;
+		}
+		if(inlen) {
+			ret = verify_area(VERIFY_READ, (char *) ioc.ui.fcs.buffer, length);
+			if (ret) return ret;
 		}
 
-		/* How many pages required of size PAGE_SIZE */
-		npages = ioc.ui.fcs.length / PAGE_SIZE;
-		/* Do we need one more? */
-
-		if (ioc.ui.fcs.length % PAGE_SIZE)
-			npages++;
-
-		/* ioctl does not support data xfer > 32KB */
-		if (npages == 1)
-			order = 0;
-		else if (npages == 2)
-			order = 1;
-		else if (npages <= 4)
-			order = 2;
-		else if (npages <= 8)
-			order = 3;
-		else
-			return -EINVAL;
-
-		if (outlen || inlen) {
-			/*
-			 * Allocate kernel space for npages.
-			 *
-			 * Since we need the memory for DMA, it needs to be physically
-			 * contiguous. __get_free_pags() return consecutive free pages
-			 * in kernel space.
-			 * Note: We don't do __get_dma_pages(), since for PCI devices,
-			 * the DMA memory is not restriceted to 16M, which is ensured
-			 * by __get_dma_pages()
-			 */
-
-			if ((kphysaddr = (char *) __get_free_pages (GFP_KERNEL,
-								    order)) ==
-			    0) {
-				printk (KERN_INFO
-					"megaraid:allocation failed\n");
-				return -ENOMEM;
-			}
-
-			memset (kphysaddr, 0, npages * PAGE_SIZE);
-			ioc.ui.fcs.buffer = kphysaddr;
-
-			if (inlen) {
-				/* copyin the user data */
-				copy_from_user (kphysaddr,
-						(char *) uaddr,
-						ioc.ui.fcs.length);
+		/*
+		 * Find this host
+		 */
+		for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
+			if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
+				megacfg = (mega_host_config *)shpnt->hostdata;
+				break;
 			}
 		}
+		if(shpnt == NULL)  return -ENODEV;
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd),
-						 GFP_KERNEL | GFP_DMA);
-		memset (scsicmd, 0, sizeof (Scsi_Cmnd));
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
 #else
-		scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
+		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
 #endif
-		if (!scsicmd) {
-			if (kphysaddr)
-				free_pages ((unsigned long) kphysaddr, order);
-			return -ENOMEM;
-		}
+		if(scsicmd == NULL) return -ENOMEM;
 
-		scsicmd->host = NULL;
+		memset(scsicmd, 0, sizeof(Scsi_Cmnd));
+		scsicmd->host = shpnt;
 
-		/*
-		 * Find this host
-		 */
-		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-			if (shpnt->hostdata ==
-			    (unsigned long *) megaCtlrs[adapno])
-				scsicmd->host = shpnt;
-		}
-
-		if (scsicmd->host == NULL) {
+		if( outlen || inlen ) {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			kfree (scsicmd);
+			pdevp = &pdev;
+			memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev));
+			pdevp->dma_mask = 0xffffffff;
+#else
+			pdevp = NULL;
+#endif
+			kvaddr = dma_alloc_consistent(pdevp, length, &dma_addr);
+
+			if( kvaddr == NULL ) {
+				printk(KERN_WARNING "megaraid:allocation failed\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
+				kfree(scsicmd);
 #else
-			scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+				scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
 #endif
-			if (kphysaddr)
-				free_pages ((unsigned long) kphysaddr, order);
-			return -ENODEV;
+				return -ENOMEM;
+			}
+
+			ioc.ui.fcs.buffer = kvaddr;
+
+			if (inlen) {
+				/* copyin the user data */
+				copy_from_user(kvaddr, (char *)uaddr, length );
+			}
 		}
 
 		scsicmd->cmnd[0] = MEGADEVIOC;
-		scsicmd->request_buffer = (void *) &ioc;
+		scsicmd->request_buffer = (void *)&ioc;
 
-		init_MUTEX_LOCKED (&mimd_ioctl_sem);
+		init_MUTEX_LOCKED(&mimd_ioctl_sem);
 
 		IO_LOCK;
-		megaraid_queue (scsicmd, megadev_ioctl_done);
+		megaraid_queue(scsicmd, megadev_ioctl_done);
 
 		IO_UNLOCK;
 
-		down (&mimd_ioctl_sem);
+		down(&mimd_ioctl_sem);
 
-		if (!scsicmd->result && outlen) {
-			copy_to_user (uaddr, kphysaddr, ioc.ui.fcs.length);
+		if( !scsicmd->result && outlen ) {
+			copy_to_user(uaddr, kvaddr, length);
 		}
 
 		/*
 		 * copyout the result
 		 */
-		uioc = (struct uioctl_t *) arg;
+		uioc = (struct uioctl_t *)arg;
 
-		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
-			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+		if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+			put_user( scsicmd->result, &uioc->pthru.scsistatus );
 		} else {
-			put_user (1, &uioc->mbox[16]);	/* numstatus */
+			put_user(1, &uioc->mbox[16]);	/* numstatus */
 			/* status */
 			put_user (scsicmd->result, &uioc->mbox[17]);
 		}
 
-		if (kphysaddr) {
-			free_pages ((ulong) kphysaddr, order);
+		if (kvaddr) {
+			dma_free_consistent(pdevp, length, kvaddr, dma_addr);
 		}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
 		kfree (scsicmd);
 #else
-		scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+		scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
 #endif
 
+		/* restore the user address */
+		ioc.ui.fcs.buffer = uaddr;
+
 		return ret;
 
 	case M_RD_IOCTL_CMD:
 		/* which adapter?  */
 		adapno = ioc.ui.fcs.adapno;
+
 		/* See comment above: MEGAIOC_QADAPINFO */
 		adapno = GETADAP (adapno);
 
@@ -4070,85 +4121,74 @@
 		outlen = ioc.outlen;
 		inlen = ioc.inlen;
 
-		if ((outlen >= IOCTL_MAX_DATALEN)
-		    || (inlen >= IOCTL_MAX_DATALEN))
+		if ((outlen >= IOCTL_MAX_DATALEN) || (inlen >= IOCTL_MAX_DATALEN))
 			return (-EINVAL);
 
 		if (outlen) {
 			ret = verify_area (VERIFY_WRITE, ioc.data, outlen);
-			if (ret)
-				return ret;
-		} else if (inlen) {
+			if (ret) return ret;
+		}
+		if (inlen) {
 			ret = verify_area (VERIFY_READ, ioc.data, inlen);
+			if (ret) return ret;
+		}
 
-			if (ret)
-				return ret;
+		/*
+		 * Find this host
+		 */
+		for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
+			if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
+				megacfg = (mega_host_config *)shpnt->hostdata;
+				break;
+			}
 		}
+		if(shpnt == NULL)  return -ENODEV;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+#else
+		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
+							  GFP_ATOMIC | GFP_DMA);
+#endif
+		if(scsicmd == NULL) return -ENOMEM;
+
+		memset(scsicmd, 0, sizeof(Scsi_Cmnd));
+		scsicmd->host = shpnt;
 
 		if (outlen || inlen) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pdevp = &pdev;
+			memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev));
+			pdevp->dma_mask = 0xffffffff;
+#else
+			pdevp = NULL;
+#endif
 			/*
 			 * Allocate a page of kernel space.
 			 */
-			if ((kphysaddr =
-			     (char *) __get_free_pages (GFP_KERNEL, 0)) == 0) {
+			kvaddr = dma_alloc_consistent(pdevp, PAGE_SIZE, &dma_addr);
 
-				printk (KERN_INFO
-					"megaraid:allocation failed\n");
+			if( kvaddr == NULL ) {
+				printk (KERN_WARNING "megaraid:allocation failed\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
+				kfree(scsicmd);
+#else
+				scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
+#endif
 				return -ENOMEM;
 			}
 
-			memset (kphysaddr, 0, PAGE_SIZE);
-			ioc.data = kphysaddr;
+			ioc.data = kvaddr;
 
 			if (inlen) {
 				if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
 					/* copyin the user data */
-					copy_from_user (kphysaddr,
-							uaddr,
-							ioc.pthru.dataxferlen);
+					copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen);
 				} else {
-					copy_from_user (kphysaddr,
-							uaddr, inlen);
+					copy_from_user (kvaddr, uaddr, inlen);
 				}
 			}
 		}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
-		scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd),
-						 GFP_KERNEL | GFP_DMA);
-		memset (scsicmd, 0, sizeof (Scsi_Cmnd));
-#else
-		scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
-							  GFP_ATOMIC | GFP_DMA);
-#endif
-
-		if (!scsicmd) {
-			if (kphysaddr)
-				free_pages ((unsigned long) kphysaddr, 0);
-			return -ENOMEM;
-		}
-
-		scsicmd->host = NULL;
-
-		/*
-		 * Find this host in the hostlist
-		 */
-		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-			if (shpnt->hostdata ==
-			    (unsigned long *) megaCtlrs[adapno])
-				scsicmd->host = shpnt;
-		}
-
-		if (scsicmd->host == NULL) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			kfree (scsicmd);
-#else
-			scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
-#endif
-			if (kphysaddr)
-				free_pages ((unsigned long) kphysaddr, 0);
-
-			return -ENODEV;
-		}
 
 		scsicmd->cmnd[0] = MEGADEVIOC;
 		scsicmd->request_buffer = (void *) &ioc;
@@ -4163,10 +4203,9 @@
 
 		if (!scsicmd->result && outlen) {
 			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
-				copy_to_user (uaddr,
-					      kphysaddr, ioc.pthru.dataxferlen);
+				copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen);
 			} else {
-				copy_to_user (uaddr, kphysaddr, outlen);
+				copy_to_user (uaddr, kvaddr, outlen);
 			}
 		}
 
@@ -4183,26 +4222,31 @@
 			put_user (scsicmd->result, &uioc->mbox[17]);
 		}
 
-		if (kphysaddr)
-			free_pages ((unsigned long) kphysaddr, 0);
+		if (kvaddr) {
+			dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr );
+		}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		kfree (scsicmd);
 #else
-		scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+		scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
 #endif
+
+		/* restore user pointer */
+		ioc.data = uaddr;
+
 		return ret;
 
 	default:
 		return (-EINVAL);
 
-	}			/* Outer switch */
+	}/* Outer switch */
 
 	return 0;
 }
 
 static void
-megadev_ioctl_done (Scsi_Cmnd * sc)
+megadev_ioctl_done(Scsi_Cmnd *sc)
 {
 	up (&mimd_ioctl_sem);
 }
@@ -4309,6 +4353,94 @@
 #endif
 	return 0;
 }
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+void *
+dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr)
+{
+	void	*_tv;
+	int		npages;
+	int		order = 0;
+
+	/*
+	 * How many pages application needs
+	 */
+	npages = size / PAGE_SIZE;
+
+	/* Do we need one more page */
+	if(size % PAGE_SIZE)
+		npages++;
+
+	order = mega_get_order(npages);
+
+	_tv = (void *)__get_free_pages(GFP_DMA, order);
+
+	if( _tv != NULL ) {
+		memset(_tv, 0, size);
+		*(dma_addr) = virt_to_bus(_tv);
+	}
+
+	return _tv;
+}
+
+/*
+ * int mega_get_order(int)
+ *
+ * returns the order to be used as 2nd argument to __get_free_pages() - which
+ * return pages equal to pow(2, order) - AM
+ */
+int
+mega_get_order(int n)
+{
+	int		i = 0;
+
+	while( pow_2(i++) < n )
+		; /* null statement */
+
+	return i-1;
+}
+
+/*
+ * int pow_2(int)
+ *
+ * calculates pow(2, i)
+ */
+int
+pow_2(int i)
+{
+	unsigned int	v = 1;
+	
+	while(i--)
+		v <<= 1;
+
+	return v;
+}
+
+void
+dma_free_consistent(void *dev, size_t size, void *vaddr, dma_addr_t dma_addr)
+{
+	int		npages;
+	int		order = 0;
+
+	npages = size / PAGE_SIZE;
+
+	if(size % PAGE_SIZE)
+		npages++;
+
+	if (npages == 1)
+		order = 0;
+	else if (npages == 2)
+		order = 1;
+	else if (npages <= 4)
+		order = 2;
+	else
+		order = 3;
+
+	free_pages((unsigned long)vaddr, order);
+
+}
+#endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.4.6/linux/drivers/scsi/megaraid.h	Fri Apr 13 20:26:07 2001
+++ linux/drivers/scsi/megaraid.h	Wed Jul  4 11:50:39 2001
@@ -27,7 +27,8 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.14g-ac2 (Release Date: Mar 22, 2001; 19:34:02)"
+#define MEGARAID_VERSION "v1.15d (Release Date: Wed May 30 17:30:41 EDT 2001)"
+
 #define MEGARAID_IOCTL_VERSION 	114
 
 /* Methods */
@@ -115,6 +116,23 @@
 #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)
 
+/* Define AMI's PCI codes */
+#ifndef PCI_VENDOR_ID_AMI
+#define PCI_VENDOR_ID_AMI		0x101E
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID
+#define PCI_DEVICE_ID_AMI_MEGARAID	0x9010
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID2
+#define PCI_DEVICE_ID_AMI_MEGARAID2	0x9060
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID3
+#define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
+#endif
+
 /* Special Adapter Commands */
 #define FW_FIRE_WRITE   	0x2C
 #define FW_FIRE_FLASH   	0x2D
@@ -829,15 +847,15 @@
  *
  *================================================================
  */
-static const char *megaraid_info (struct Scsi_Host *);
+const char *megaraid_info (struct Scsi_Host *);
 int megaraid_detect (Scsi_Host_Template *);
-static int megaraid_release (struct Scsi_Host *);
-static int megaraid_command (Scsi_Cmnd *);
-static int megaraid_abort (Scsi_Cmnd *);
-static int megaraid_reset (Scsi_Cmnd *, unsigned int);
-static int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int megaraid_biosparam (Disk *, kdev_t, int *);
-static int megaraid_proc_info (char *buffer, char **start, off_t offset,
+int megaraid_release (struct Scsi_Host *);
+int megaraid_command (Scsi_Cmnd *);
+int megaraid_abort (Scsi_Cmnd *);
+int megaraid_reset (Scsi_Cmnd *, unsigned int);
+int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int megaraid_biosparam (Disk *, kdev_t, int *);
+int megaraid_proc_info (char *buffer, char **start, off_t offset,
 			int length, int hostno, int inout);
 
 static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData,
@@ -855,7 +873,7 @@
 
 static int megaraid_reboot_notify (struct notifier_block *,
 				   unsigned long, void *);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)  
 static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
 static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb,
 			   mega_ioctl_mbox * mbox);
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.4.6/linux/drivers/scsi/ncr53c8xx.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/ncr53c8xx.c	Thu Jul  5 11:28:17 2001
@@ -103,7 +103,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx-3.4.3-20010212"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx-3.4.3b-20010512"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -3082,7 +3082,7 @@
 };
 
 /*
-**	Print something which allows to retrieve the controler type, unit,
+**	Print something which allows to retrieve the controller type, unit,
 **	target, lun concerned by a kernel message.
 */
 
@@ -4302,7 +4302,7 @@
 	**
 	**----------------------------------------------------
 	*/
-#if 0	/* This stuff was only usefull for linux-1.2.13 */
+#if 0	/* This stuff was only useful for linux-1.2.13 */
 	if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
 		lp->numtags = tp->usrtags;
 		ncr_setup_tags (np, cmd->target, cmd->lun);
@@ -5701,7 +5701,7 @@
 	*/
 	fak = (kpc - 1) / div_10M[div] + 1;
 
-#if 0	/* This optimization does not seem very usefull */
+#if 0	/* This optimization does not seem very useful */
 
 	per = (fak * div_10M[div]) / clk;
 
@@ -6647,7 +6647,7 @@
 			delta=(INB (nc_dfifo) - rest) & 0x7f;
 
 		/*
-		**	The data in the dma fifo has not been transfered to
+		**	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.
@@ -7153,7 +7153,7 @@
 **	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
+**	a successful inquire command. We look at byte 7 of the
 **	inquire data to determine the capabilities of the target.
 **
 **	When we try to negotiate, we append the negotiation message
@@ -7550,7 +7550,7 @@
 /*==========================================================
 **
 **
-**	Aquire a control block
+**	Acquire a control block
 **
 **
 **==========================================================
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- v2.4.6/linux/drivers/scsi/osst.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/osst.c	Wed Jul  4 15:39:28 2001
@@ -321,7 +321,8 @@
 		}
 	}
 
-	cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
+        if (SRpnt->sr_device->scsi_level <= SCSI_2)
+                cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
 	init_MUTEX_LOCKED(&STp->sem);
 	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
 				    (STp->buffer)->use_sg : 0;
@@ -712,7 +713,7 @@
 		result = osst_get_frame_position (STp, aSRpnt);
 		if (result == -EIO)
 			if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
-				return 0;	/* successfull recovery leaves drive ready for frame */
+				return 0;	/* successful recovery leaves drive ready for frame */
 		if (result < 0) break;
 		if (STp->first_frame_position == curr &&
 		    ((minlast < 0 &&
@@ -1379,7 +1380,7 @@
 	unsigned char	cmd[MAX_COMMAND_SIZE];
 	Scsi_Request  * SRpnt;
 	int		dev       = TAPE_NR(STp->devt);
-	int		expected  = 0;
+	int		expected  __attribute__ ((__unused__));
 	int		attempts  = 1000 / skip;
 	int		flag      = 1;
 	long		startwait = jiffies;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/osst.h linux/drivers/scsi/osst.h
--- v2.4.6/linux/drivers/scsi/osst.h	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/osst.h	Wed Jul  4 15:39:28 2001
@@ -595,7 +595,7 @@
 						* has been read into STp->buffer and is valid */
   int      frame_seq_number;                   /* logical frame number */
   int      logical_blk_num;                    /* logical block number */
-  unsigned first_frame_position;               /* physical frame to be transfered to/from host */
+  unsigned first_frame_position;               /* physical frame to be transferred to/from host */
   unsigned last_frame_position;                /* physical frame to be transferd to/from tape */
   int      cur_frames;                         /* current number of frames in internal buffer */
   int      max_frames;                         /* max number of frames in internal buffer */
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/Config.in linux/drivers/scsi/pcmcia/Config.in
--- v2.4.6/linux/drivers/scsi/pcmcia/Config.in	Sun Mar  4 14:30:19 2001
+++ linux/drivers/scsi/pcmcia/Config.in	Wed Jul  4 11:50:38 2001
@@ -8,12 +8,13 @@
 bool 'PCMCIA SCSI adapter support' CONFIG_SCSI_PCMCIA
 if [ "$CONFIG_SCSI_PCMCIA" = "y" ]; then
    dep_tristate '  Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m
-   dep_tristate '  Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m
    dep_tristate '  Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m
+   dep_tristate	'  NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support' CONFIG_PCMCIA_NINJA_SCSI m
+   dep_tristate '  Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m
 fi
 
 if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \
-     "$CONFIG_PCMCIA_FDOMAIN" = "y" ]; then
+     "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_NINJA_SCSI" = "y" ]; then
    define_bool CONFIG_PCMCIA_SCSICARD y
 fi
 
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/Makefile linux/drivers/scsi/pcmcia/Makefile
--- v2.4.6/linux/drivers/scsi/pcmcia/Makefile	Mon Mar 26 15:36:30 2001
+++ linux/drivers/scsi/pcmcia/Makefile	Wed Jul  4 11:50:38 2001
@@ -19,6 +19,7 @@
 obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogic_cs.o
 obj-$(CONFIG_PCMCIA_FDOMAIN)	+= fdomain_cs.o
 obj-$(CONFIG_PCMCIA_AHA152X)	+= aha152x_cs.o
+obj-$(CONFIG_PCMCIA_NINJA_SCSI)	+= nsp_cs.o
 
 list-multi	:= qlogic_cs.o fdomain_cs.o aha152x_cs.o
 aha152x_cs-objs	:= aha152x_stub.o aha152x.o
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c
--- v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/nsp_cs.c	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,1714 @@
+/*======================================================================
+
+    NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI hostadapter card driver
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+    Ver.2.0   Support 32bit PIO mode
+    Ver.1.1.2 Fix for scatter list buffer exceeds
+    Ver.1.1   Support scatter list
+    Ver.0.1   Initial version
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License.
+
+======================================================================*/
+
+/***********************************************************************
+    This driver is for these PCcards.
+
+	I-O DATA PCSC-F	 (Workbit NinjaSCSI-3)
+			"WBT", "NinjaSCSI-3", "R1.0"
+	I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
+			"IO DATA", "CBSC16	 ", "1"
+
+***********************************************************************/
+
+/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */
+
+#ifdef NSP_KERNEL_2_2
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/stat.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <../drivers/scsi/sd.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "nsp_cs.h"
+
+MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+MODULE_PARM_DESC(pc_debug, "set debug level");
+static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...) /* */
+#endif
+
+#include "nsp_io.h"
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+	dev_link_t             link;
+	struct Scsi_Host      *host;
+	int	               ndev;
+	dev_node_t             node[8];
+	int                    stop;
+	struct bus_operations *bus;
+} scsi_info_t;
+
+static void nsp_release(u_long arg);
+static int nsp_event(event_t event, int priority,
+		     event_callback_args_t *args);
+static dev_link_t *nsp_attach(void);
+static void nsp_detach(dev_link_t *);
+static int nsp_detect(Scsi_Host_Template * );
+static const char * nsp_info(struct Scsi_Host *);
+static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+static int nsp_abort(Scsi_Cmnd *);
+static int nsp_reset(Scsi_Cmnd *, unsigned int);
+
+
+/*----------------------------------------------------------------*/
+
+#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE)
+#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */
+static struct proc_dir_entry proc_scsi_nsp = {
+	PROC_SCSI_NSP, 6, "nsp_cs",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+
+/*====================================================================*/
+/* Parameters that can be set with 'insmod' */
+
+static unsigned int irq_mask = 0xffff;
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM_DESC(irq_mask, "IRQ mask bits");
+
+static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM_DESC(irq_list, "IRQ number list");
+
+/*----------------------------------------------------------------*/
+/* driver state info, local to driver */
+static char nspinfo[100];     /* description */
+
+/* /usr/src/linux/drivers/scsi/hosts.h */
+static Scsi_Host_Template driver_template = {
+/*	next:			NULL,*/
+/*	proc_dir:		NULL,*/
+/*	proc_info:		NULL,*/
+	name:			"WorkBit NinjaSCSI-3/32Bi",
+	detect:			nsp_detect,
+/*	release:		NULL,*/
+	info:			nsp_info,
+/*	command:		NULL,*/
+	queuecommand:		nsp_queuecommand,
+/*	eh_strategy_handler:	nsp_eh_strategy,*/
+/*	eh_abort_handler:	nsp_eh_abort,*/
+/*	eh_device_reset_handler: nsp_eh_device_reset,*/
+	eh_bus_reset_handler:	nsp_eh_bus_reset,
+/*	eh_host_reset_handler:	nsp_eh_host_reset,*/
+	abort:			nsp_abort,
+	reset:			nsp_reset,
+/*	slave_attach:		NULL,*/
+/*	bios_param:		nsp_biosparam,*/
+	can_queue:		1,
+	this_id:		-1,
+	sg_tablesize:		SG_ALL,
+	cmd_per_lun:		1,
+/*	present:		0,*/
+/*	unchecked_isa_dma:	0,*/
+	use_clustering:		DISABLE_CLUSTERING,
+	use_new_eh_code:	0,
+/*	emulated:		0,*/
+};
+
+static dev_link_t *dev_list = NULL;
+static dev_info_t dev_info  = {"nsp_cs"};
+
+static nsp_hw_data nsp_data;
+
+/***********************************************************/
+
+static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+#ifdef PCMCIA_DEBUG
+	//unsigned int host_id = SCpnt->host->this_id;
+	//unsigned int base    = SCpnt->host->io_port;
+	unsigned char target = SCpnt->target;
+#endif
+
+	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",
+	      SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
+	//DEBUG(0, " before CurrentSC=0x%p\n", nsp_data.CurrentSC);
+
+	if(nsp_data.CurrentSC != NULL) {
+		printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n");
+		nsp_data.CurrentSC = NULL;
+		SCpnt->result	   = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return FAILED;
+	}
+
+#ifdef PCMCIA_DEBUG
+	show_command(SCpnt);
+#endif
+
+	SCpnt->scsi_done	= done;
+	nsp_data.CurrentSC	= SCpnt;
+	RESID		        = SCpnt->request_bufflen;
+
+	SCpnt->SCp.Status	= -1;
+	SCpnt->SCp.Message	= -1;
+	SCpnt->SCp.have_data_in = IO_UNKNOWN;
+	SCpnt->SCp.sent_command = 0;
+	SCpnt->SCp.phase	= PH_UNDETERMINED;
+
+	/* setup scratch area
+	   SCp.ptr		: buffer pointer
+	   SCp.this_residual	: buffer length
+	   SCp.buffer		: next buffer
+	   SCp.buffers_residual : left buffers in list
+	   SCp.phase		: current state of the command */
+	if (SCpnt->use_sg) {
+		SCpnt->SCp.buffer	    = (struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.ptr		    = SCpnt->SCp.buffer->address;
+		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+	} else {
+		SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer	    = NULL;
+		SCpnt->SCp.buffers_residual = 0;
+	}
+
+	if(nsphw_start_selection(SCpnt) == FALSE) {
+		DEBUG(0, " selection fail\n");
+		nsp_data.CurrentSC = NULL;
+		SCpnt->result	   = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return FAILED;
+	}
+
+
+	//DEBUG(0, __FUNCTION__ "() out\n");
+	return SUCCESS;
+}
+
+/*
+ * setup PIO FIFO transfer mode and enable/disable to data out
+ */
+static void nsp_setup_fifo(unsigned int base, int enabled)
+{
+	unsigned char transfer_mode;
+
+	//DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled);
+
+	if (enabled != FALSE) {
+		transfer_mode = TRANSFER_GO | BRAIND;
+	} else {
+		transfer_mode = 0;
+	}
+
+	transfer_mode |= nsp_data.TransferMode;
+
+	nsp_index_write(base, TRANSFERMODE, transfer_mode);
+}
+
+/*
+ * Initialize Ninja hardware
+ */
+static int nsphw_init(void)
+{
+	unsigned int base     = nsp_data.BaseAddress;
+	int	     i, j;
+	sync_data    tmp_sync = { SyncNegotiation: SYNC_NOT_YET,
+				  SyncPeriod:	   0,
+				  SyncOffset:	   0
+	};
+
+	//DEBUG(0, __FUNCTION__ "() in\n");
+
+	nsp_data.ScsiClockDiv = CLOCK_40M;
+	nsp_data.CurrentSC    = NULL;
+	nsp_data.FifoCount    = 0;
+	nsp_data.TransferMode = MODE_IO8;
+
+	/* setup sync data */
+	for ( i = 0; i < N_TARGET; i++ ) {
+		for ( j = 0; j < N_LUN; j++ ) {
+			nsp_data.Sync[i][j] = tmp_sync;
+		}
+	}
+
+	/* block all interrupts */
+	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLMASK);
+
+	/* setup SCSI interface */
+	nsp_write(base,	      IFSELECT,	    IF_IFSEL);
+
+	nsp_index_write(base, SCSIIRQMODE,  0);
+
+	nsp_index_write(base, TRANSFERMODE, MODE_IO8);
+	nsp_index_write(base, CLOCKDIV,	    nsp_data.ScsiClockDiv);
+
+	nsp_index_write(base, PARITYCTRL,   0);
+	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |
+					    ACK_COUNTER_CLEAR |
+					    REQ_COUNTER_CLEAR |
+					    HOST_COUNTER_CLEAR);
+
+	/* setup fifo asic */
+	nsp_write(base,	      IFSELECT,	    IF_REGSEL);
+	nsp_index_write(base, TERMPWRCTRL,  0);
+	if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
+		printk(KERN_INFO "nsp_cs: terminator power on\n");
+		nsp_index_write(base, TERMPWRCTRL, POWER_ON);
+	}
+
+	nsp_index_write(base, TIMERCOUNT,   0);
+	nsp_index_write(base, TIMERCOUNT,   0); /* requires 2 times!! */
+
+	nsp_index_write(base, SYNCREG,	    0);
+	nsp_index_write(base, ACKWIDTH,	    0);
+
+	/* enable interrupts and ack them */
+	nsp_index_write(base, SCSIIRQMODE,  SCSI_PHASE_CHANGE_EI |
+					    RESELECT_EI		 |
+					    SCSI_RESET_IRQ_EI	 );
+	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLCLEAR);
+
+	nsp_setup_fifo(base, FALSE);
+
+	return TRUE;
+}
+
+/*
+ * Start selection phase
+ */
+static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  host_id	 = SCpnt->host->this_id;
+	unsigned int  base	 = SCpnt->host->io_port;
+	unsigned char target	 = SCpnt->target;
+	int	      wait_count;
+	unsigned char phase, arbit;
+
+	//DEBUG(0, __FUNCTION__ "()in\n");
+
+
+	phase = nsp_index_read(base, SCSIBUSMON);
+	if(phase != BUSMON_BUS_FREE) {
+		//DEBUG(0, " bus busy\n");
+		return FALSE;
+	}
+
+	/* start arbitration */
+	//DEBUG(0, " start arbit\n");
+	SCpnt->SCp.phase = PH_ARBSTART;
+	nsp_index_write(base, SETARBIT, ARBIT_GO);
+
+	wait_count = jiffies + 10 * HZ;
+	do {
+		/* XXX: what a stupid chip! */
+		arbit = nsp_index_read(base, ARBITSTATUS);
+		//DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count);
+		udelay(1); /* hold 1.2us */
+	} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
+		time_before(jiffies, wait_count));
+
+	if((arbit & ARBIT_WIN) == 0) {
+		//DEBUG(0, " arbit fail\n");
+		nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
+		return FALSE;
+	}
+
+	/* assert select line */
+	//DEBUG(0, " assert SEL line\n");
+	SCpnt->SCp.phase = PH_SELSTART;
+	udelay(3);
+	nsp_index_write(base, SCSIDATALATCH, (1 << host_id) | (1 << target));
+	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_ATN);
+	udelay(3);
+	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
+	nsp_index_write(base, SETARBIT,	     ARBIT_FLAG_CLEAR);
+	udelay(3);
+	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
+
+	/* check selection timeout */
+	nsp_start_timer(SCpnt, 1000/51);
+	nsp_data.SelectionTimeOut = 1;
+
+	return TRUE;
+}
+
+struct nsp_sync_table {
+	unsigned int min_period;
+	unsigned int max_period;
+	unsigned int chip_period;
+	unsigned int ack_width;
+};
+
+static struct nsp_sync_table nsp_sync_table_40M[] = {
+	{0x0c,0x0c,0x1,0},	/* 20MB	 50ns*/
+	{0x19,0x19,0x3,1},	/* 10MB	 100ns*/ 
+	{0x1a,0x25,0x5,2},	/* 7.5MB 150ns*/ 
+	{0x26,0x32,0x7,3},	/* 5MB	 200ns*/
+	{0x0, 0,   0,  0}
+};
+
+static struct nsp_sync_table nsp_sync_table_20M[] = {
+	{0x19,0x19,0x1,0},	/* 10MB	 100ns*/ 
+	{0x1a,0x25,0x2,0},	/* 7.5MB 150ns*/ 
+	{0x26,0x32,0x3,1},	/* 5MB	 200ns*/
+	{0x0, 0,   0,  0}
+};
+
+/*
+ * setup synchronous data transfer mode
+ */
+static int nsp_msg(Scsi_Cmnd *SCpnt)
+{
+	unsigned char	       target = SCpnt->target;
+	unsigned char	       lun    = SCpnt->lun;
+	sync_data	      *sync   = &(nsp_data.Sync[target][lun]);
+	struct nsp_sync_table *sync_table;
+	unsigned int	       period, offset;
+	int		       i;
+
+
+	DEBUG(0, __FUNCTION__ "()\n");
+
+/**!**/
+
+	period = sync->SyncPeriod;
+	offset = sync->SyncOffset;
+
+	DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset);
+
+	if (nsp_data.ScsiClockDiv == CLOCK_20M) {
+		sync_table = &nsp_sync_table_20M[0];
+	} else {
+		sync_table = &nsp_sync_table_40M[0];
+	}
+
+	for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
+		if ( period >= sync_table->min_period &&
+		     period <= sync_table->max_period	 ) {
+			break;
+		}
+	}
+
+	if (period != 0 && sync_table->max_period == 0) {
+		/*
+		 * No proper period/offset found
+		 */
+		DEBUG(0, " no proper period/offset\n");
+
+		sync->SyncPeriod   = 0;
+		sync->SyncOffset   = 0;
+		sync->SyncRegister = 0;
+		sync->AckWidth	   = 0;
+
+		return FALSE;
+	}
+
+	sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
+			     (offset & SYNCREG_OFFSET_MASK);
+	sync->AckWidth	   = sync_table->ack_width;
+
+	DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth);
+
+	return TRUE;
+}
+
+
+/*
+ * start ninja hardware timer
+ */
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
+{
+	unsigned int base = SCpnt->host->io_port;
+
+	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time);
+	nsp_data.TimerCount = time;
+	nsp_index_write(base, TIMERCOUNT, time);
+}
+
+/*
+ * wait for bus phase change
+ */
+static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str)
+{
+	unsigned int  base = SCpnt->host->io_port;
+	unsigned char reg;
+	int	      count, i = TRUE;
+
+	//DEBUG(0, __FUNCTION__ "()\n");
+
+	count = jiffies + HZ;
+
+	do {
+		reg = nsp_index_read(base, SCSIBUSMON);
+		if (reg == 0xff) {
+			break;
+		}
+	} while ((i = time_before(jiffies, count)) && (reg & mask) != 0);
+
+	if (!i) {
+		printk(KERN_DEBUG __FUNCTION__ " %s signal off timeut\n", str);
+	}
+
+	return 0;
+}
+
+/*
+ * expect Ninja Irq
+ */
+static int nsp_expect_signal(Scsi_Cmnd	   *SCpnt,
+			     unsigned char  current_phase,
+			     unsigned char  mask)
+{
+	unsigned int  base	 = SCpnt->host->io_port;
+	int	      wait_count;
+	unsigned char phase, i_src;
+
+	//DEBUG(0, __FUNCTION__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask);
+
+	wait_count = jiffies + HZ;
+	do {
+		phase = nsp_index_read(base, SCSIBUSMON);
+		if (phase == 0xff) {
+			//DEBUG(0, " ret -1\n");
+			return -1;
+		}
+		i_src = nsp_read(base, IRQSTATUS);
+		if (i_src & IRQSTATUS_SCSI) {
+			//DEBUG(0, " ret 0 found scsi signal\n");
+			return 0;
+		}
+		if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
+			//DEBUG(0, " ret 1 phase=0x%x\n", phase);
+			return 1;
+		}
+	} while(time_before(jiffies, wait_count));
+
+	//DEBUG(0, __FUNCTION__ " : " __FUNCTION__ " timeout\n");
+	return -1;
+}
+
+/*
+ * transfer SCSI message
+ */
+static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
+{
+	unsigned int  base = SCpnt->host->io_port;
+	char	     *buf  = nsp_data.MsgBuffer;
+	int	      len  = MIN(MSGBUF_SIZE, nsp_data.MsgLen);
+	int	      ptr;
+	int	      ret;
+
+	//DEBUG(0, __FUNCTION__ "()\n");
+/**!**/
+	for (ptr = 0; len > 0; len --, ptr ++) {
+
+		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
+		if (ret <= 0) {
+			DEBUG(0, " xfer quit\n");
+			return 0;
+		}
+
+		/* if last byte, negate ATN */
+		if (len == 1) {
+			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
+		}
+
+		/* read & write message */
+		if (phase & BUSMON_IO) {
+			//DEBUG(0, " read msg\n");
+			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
+		} else {
+			//DEBUG(0, " write msg\n");
+			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
+		}
+		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
+
+	}
+	return len;
+}
+
+/*
+ * get extra SCSI data from fifo
+ */
+static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = SCpnt->host->io_port;
+	unsigned int count;
+
+	//DEBUG(0, __FUNCTION__ "()\n");
+
+	if (SCpnt->SCp.have_data_in != IO_IN) {
+		return 0;
+	}
+
+	count = nsp_fifo_count(SCpnt);
+	if (nsp_data.FifoCount == count) {
+		//DEBUG(0, " not use bypass quirk\n");
+		return 0;
+	}
+
+	/*
+	 * XXX: NSP_QUIRK
+	 * data phase skip only occures in case of SCSI_LOW_READ
+	 */
+	SCpnt->SCp.phase = PH_DATA;
+	nsp_pio_read(SCpnt);
+	nsp_setup_fifo(base, FALSE);
+
+	DEBUG(0, " use bypass quirk\n");
+	return 0;
+}
+
+/*
+ * accept reselection
+ */
+static int nsp_reselected(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base = SCpnt->host->io_port;
+	unsigned char reg;
+
+	//DEBUG(0, __FUNCTION__ "()\n");
+
+	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
+
+	nsp_nexus(SCpnt);
+	reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
+	nsp_index_write(base, SCSIBUSCTRL, reg);
+	nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB);
+
+	return TRUE;
+}
+
+/*
+ * count how many data transferd
+ */
+static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = SCpnt->host->io_port;
+	unsigned int count;
+	unsigned int l, m, h;
+
+	nsp_index_write(base, POINTERCLR, POINTER_CLEAR);
+
+        l = (unsigned int)nsp_read(base, DATAREG);
+        m = (unsigned int)nsp_read(base, DATAREG);
+        h = (unsigned int)nsp_read(base, DATAREG);
+
+	count = (h << 16) | (m << 8) | (l << 0);
+
+	//DEBUG(0, __FUNCTION__ "() =0x%x\n", count);
+
+	return count;
+}
+
+/* fifo size */
+#define RFIFO_CRIT 64
+#define WFIFO_CRIT 64
+
+/*
+ * read data in DATA IN phase
+ */
+static void nsp_pio_read(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base     = SCpnt->host->io_port;
+	int	      time_out, i;
+	int	      ocount, res;
+	unsigned char stat, fifo_stat;
+
+	ocount = nsp_data.FifoCount;
+
+	DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
+
+	time_out = jiffies + 10 * HZ;
+
+	while ((i = time_before(jiffies,time_out)) &&
+	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
+
+		stat = nsp_index_read(base, SCSIBUSMON);
+		stat &= BUSMON_PHASE_MASK;
+
+		res = nsp_fifo_count(SCpnt) - ocount;
+
+		//DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res);
+		if (res == 0) { /* if some data avilable ? */
+			if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
+				//DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual);
+				continue;
+			} else {
+				DEBUG(0, " phase changed stat=0x%x\n", stat);
+				break;
+			}
+		}
+
+		fifo_stat = nsp_read(base, FIFOSTATUS);
+		if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
+		    stat                                == BUSPHASE_DATA_IN) {
+			continue;
+		}
+
+		res = MIN(res, SCpnt->SCp.this_residual);
+
+		switch (nsp_data.TransferMode) {
+		case MODE_IO32:
+			res &= ~(BIT(1)|BIT(0)); /* align 4 */
+			nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
+			break;
+		case MODE_IO8:
+			nsp_fifo8_read (base, SCpnt->SCp.ptr, res     );
+			break;
+		default:
+			DEBUG(0, "unknown read mode\n");
+			break;
+		}
+
+		RESID			 -= res;
+		SCpnt->SCp.ptr		 += res;
+		SCpnt->SCp.this_residual -= res;
+		ocount			 += res;
+		//DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
+
+		/* go to next scatter list if availavle */
+		if (SCpnt->SCp.this_residual	== 0 &&
+		    SCpnt->SCp.buffers_residual != 0 ) {
+			//DEBUG(0, " scatterlist next timeout=%d\n", time_out);
+			SCpnt->SCp.buffers_residual--;
+			SCpnt->SCp.buffer++;
+			SCpnt->SCp.ptr		 = SCpnt->SCp.buffer->address;
+			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+		}
+
+		time_out = jiffies + 10 * HZ;
+	}
+
+	nsp_data.FifoCount = ocount;
+
+	if (!i) {
+		printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
+	}
+	DEBUG(0, " read ocount=0x%x\n", ocount);
+}
+
+/*
+ * write data in DATA OUT phase
+ */
+static void nsp_pio_write(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base     = SCpnt->host->io_port;
+	int	      time_out, i;
+	unsigned int  ocount, res;
+	unsigned char stat;
+
+	ocount	 = nsp_data.FifoCount;
+
+	DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", nsp_data.FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
+
+	time_out = jiffies + 10 * HZ;
+
+	while ((i = time_before(jiffies, time_out))                             &&
+	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
+		stat = nsp_index_read(base, SCSIBUSMON);
+		stat &= BUSMON_PHASE_MASK;
+		if (stat != BUSPHASE_DATA_OUT) {
+			DEBUG(0, " phase changed stat=0x%x\n", stat);
+			break;
+		}
+
+		res = ocount - nsp_fifo_count(SCpnt);
+		if (res > 0) { /* write all data? */
+			DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res);
+			continue;
+		}
+
+		res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT);
+
+		//DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
+		switch (nsp_data.TransferMode) {
+		case MODE_IO32:
+			res &= ~(BIT(1)|BIT(0)); /* align 4 */
+			nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
+			break;
+		case MODE_IO8:
+			nsp_fifo8_write (base, SCpnt->SCp.ptr, res     );
+			break;
+		default:
+			DEBUG(0, "unknown write mode\n");
+			break;
+		}
+
+		RESID			 -= res;
+		SCpnt->SCp.ptr		 += res;
+		SCpnt->SCp.this_residual -= res;
+		ocount			 += res;
+
+		/* go to next scatter list if availavle */
+		if (SCpnt->SCp.this_residual	== 0 &&
+		    SCpnt->SCp.buffers_residual != 0 ) {
+			//DEBUG(0, " scatterlist next\n");
+			SCpnt->SCp.buffers_residual--;
+			SCpnt->SCp.buffer++;
+			SCpnt->SCp.ptr		 = SCpnt->SCp.buffer->address;
+			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+		}
+
+		time_out = jiffies + 10 * HZ;
+	}
+
+	nsp_data.FifoCount = ocount;
+
+	if (!i) {
+		printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID);
+	}
+	//DEBUG(0, " write ocount=%d\n", ocount);
+}
+
+#undef RFIFO_CRIT
+#undef WFIFO_CRIT
+
+/*
+ * setup synchronous/asynchronous data transfer mode
+ */
+static int nsp_nexus(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base   = SCpnt->host->io_port;
+	unsigned char target = SCpnt->target;
+	unsigned char lun    = SCpnt->lun;
+	sync_data *sync = &(nsp_data.Sync[target][lun]);
+
+	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt);
+
+	/* setup synch transfer registers */
+	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
+	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
+
+	if (RESID % 4 != 0   ||
+	    RESID     <= 256 ) {
+		nsp_data.TransferMode = MODE_IO8;
+	} else {
+		nsp_data.TransferMode = MODE_IO32;
+	}
+
+	/* setup pdma fifo */
+	nsp_setup_fifo(base, TRUE);
+
+	/* clear ack counter */
+	nsp_data.FifoCount = 0;
+	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |
+					  ACK_COUNTER_CLEAR |
+					  REQ_COUNTER_CLEAR |
+					  HOST_COUNTER_CLEAR);
+
+	return 0;
+}
+
+/*
+ * interrupt handler
+ */
+static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int   base;
+	unsigned char  i_src, irq_phase, phase;
+	Scsi_Cmnd     *tmpSC;
+	int	       ret, len;
+	unsigned char  data_reg, control_reg;
+
+
+	//DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC);
+
+	base = nsp_data.BaseAddress;
+	//DEBUG(0, " base=0x%x\n", base);
+
+	/*
+	 * interrupt check
+	 */
+	nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
+	i_src = nsp_read(base, IRQSTATUS);
+	if (i_src == 0xff || (i_src & IRQSTATUS_MASK) == 0) {
+		nsp_write(base, IRQCONTROL, 0);
+		//DEBUG(0, " no irq\n");
+		return;
+	}
+
+	//DEBUG(0, " i_src=0x%x\n", i_src);
+
+	/* XXX: IMPORTANT
+	 * Do not read an irq_phase register if no scsi phase interrupt.
+	 * Unless, you should lose a scsi phase interrupt.
+	 */
+	phase = nsp_index_read(base, SCSIBUSMON);
+	if((i_src & IRQSTATUS_SCSI) != 0) {
+		irq_phase = nsp_index_read(base, IRQPHASESENCE);
+	} else {
+		irq_phase = 0;
+	}
+
+	//DEBUG(0, " irq_phase=0x%x\n", irq_phase);
+
+	/*
+	 * timer interrupt handler (scsi vs timer interrupts)
+	 */
+	//DEBUG(0, " timercount=%d\n", nsp_data.TimerCount);
+	if (nsp_data.TimerCount != 0) {
+		//DEBUG(0, " stop timer\n");
+		nsp_index_write(base, TIMERCOUNT, 0);
+		nsp_index_write(base, TIMERCOUNT, 0);
+		nsp_data.TimerCount = 0;
+	}
+
+	if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
+	    nsp_data.SelectionTimeOut == 0) {
+		//DEBUG(0, " timer start\n");
+		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
+		return;
+	}
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
+
+	if (nsp_data.CurrentSC == NULL) {
+		printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase);
+		return;
+	} else {
+		tmpSC = nsp_data.CurrentSC;
+	}
+
+	/*
+	 * parse hardware SCSI irq reasons register
+	 */
+	if ((i_src & IRQSTATUS_SCSI) != 0) {
+		if ((irq_phase & SCSI_RESET_IRQ) != 0) {
+			printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n");
+
+			nsp_data.CurrentSC = NULL;
+			tmpSC->result	   = DID_RESET << 16;
+			tmpSC->scsi_done(tmpSC);
+			return;
+		}
+
+		if ((irq_phase & RESELECT_IRQ) != 0) {
+			DEBUG(0, " reselect\n");
+			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
+			if (nsp_reselected(tmpSC) != FALSE) {
+				return;
+			}
+		}
+
+		if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
+			return; 
+		}
+	}
+
+	//show_phase(tmpSC);
+
+	switch(tmpSC->SCp.phase) {
+	case PH_SELSTART:
+		if ((phase & BUSMON_BSY) == 0) {
+			//DEBUG(0, " selection count=%d\n", nsp_data.SelectionTimeOut);
+			if (nsp_data.SelectionTimeOut >= NSP_SELTIMEOUT) {
+				DEBUG(0, " selection time out\n");
+				nsp_data.SelectionTimeOut = 0;
+				nsp_index_write(base, SCSIBUSCTRL, 0);
+
+				nsp_data.CurrentSC = NULL;
+				tmpSC->result	   = DID_NO_CONNECT << 16;
+				tmpSC->scsi_done(tmpSC);
+
+				return;
+			}
+			nsp_data.SelectionTimeOut += 1;
+			nsp_start_timer(tmpSC, 1000/51);
+			return;
+		}
+
+		/* attention assert */
+		//DEBUG(0, " attention assert\n");
+		nsp_data.SelectionTimeOut = 0;
+		tmpSC->SCp.phase	  = PH_SELECTED;
+		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
+		udelay(1);
+		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
+		return;
+
+		break;
+
+	case PH_RESELECT:
+		//DEBUG(0, " phase reselect\n");
+		if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
+
+			nsp_data.CurrentSC = NULL;
+			tmpSC->result	   = DID_ABORT << 16;
+			tmpSC->scsi_done(tmpSC);
+			return;
+		}
+		/* fall thru */
+	default:
+		if (( i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
+			return;
+		}
+		break;
+	}
+
+	/*
+	 * SCSI sequencer
+	 */
+	//DEBUG(0, " start scsi seq\n");
+
+	/* normal disconnect */
+	if ((irq_phase & LATCHED_BUS_FREE) != 0) {
+		//DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
+		if ((tmpSC->SCp.Message == 0)) {     /* all command complete and return status */
+			nsp_data.CurrentSC = NULL;
+			tmpSC->result = (DID_OK		    << 16) |
+					(tmpSC->SCp.Message <<	8) |
+					(tmpSC->SCp.Status  <<	0);
+			DEBUG(0, " command complete result=0x%x\n", tmpSC->result);
+			tmpSC->scsi_done(tmpSC);
+			return;
+		}
+
+		return;
+	}
+
+
+	/* check unexpected bus free state */
+	if (phase == 0) {
+		printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
+
+		nsp_data.CurrentSC = NULL;
+		tmpSC->result	   = DID_ERROR << 16;
+		tmpSC->scsi_done(tmpSC);
+		return;
+	}
+
+	switch (phase & BUSMON_PHASE_MASK) {
+	case BUSPHASE_COMMAND:
+		DEBUG(0, " BUSPHASE_COMMAND\n");
+		if ((phase & BUSMON_REQ) == 0) {
+			DEBUG(0, " REQ == 0\n");
+			return;
+		}
+
+		tmpSC->SCp.phase = PH_COMMAND;
+
+		nsp_nexus(tmpSC);
+
+		/* write scsi command */
+		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
+		for (len = 0; len < COMMAND_SIZE(tmpSC->cmnd[0]); len++) {
+			nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[len]);
+		}
+		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
+		break;
+
+	case BUSPHASE_DATA_OUT:
+		DEBUG(0, " BUSPHASE_DATA_OUT\n");
+
+		tmpSC->SCp.phase = PH_DATA;
+		tmpSC->SCp.have_data_in = IO_OUT;
+
+		nsp_pio_write(tmpSC);
+
+		break;
+
+	case BUSPHASE_DATA_IN:
+		DEBUG(0, " BUSPHASE_DATA_IN\n");
+
+		tmpSC->SCp.phase = PH_DATA;
+		tmpSC->SCp.have_data_in = IO_IN;
+
+		nsp_pio_read(tmpSC);
+
+		break;
+
+	case BUSPHASE_STATUS:
+		nsp_dataphase_bypass(tmpSC);
+		DEBUG(0, " BUSPHASE_STATUS\n");
+
+		tmpSC->SCp.phase = PH_STATUS;
+
+		tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
+		//DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status);
+
+		break;
+
+	case BUSPHASE_MESSAGE_OUT:
+		DEBUG(0, " BUSPHASE_MESSAGE_OUT\n");
+		if ((phase & BUSMON_REQ) == 0) {
+			goto timer_out;
+		}
+
+		tmpSC->SCp.phase = PH_MSG_OUT;
+
+		/*
+		 * XXX: NSP QUIRK
+		 * NSP invoke interrupts only in the case of scsi phase changes,
+		 * therefore we should poll the scsi phase here to catch 
+		 * the next "msg out" if exists (no scsi phase changes).
+		 */
+		ret = 16;
+		len = 0;
+
+		nsp_msg(tmpSC);
+
+		nsp_data.MsgBuffer[len] = IDENTIFY(TRUE, tmpSC->lun); len++;
+		nsp_data.MsgLen		= len;
+
+		do {
+			DEBUG(0, " msgout loop\n");
+
+			if (nsp_xfer(tmpSC, BUSPHASE_MESSAGE_OUT)) {
+				printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n");
+			}
+
+			/* catch a next signal */
+			ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_OUT, BUSMON_REQ);
+		} while (ret > 0 && len-- > 0);
+
+		break;
+
+	case BUSPHASE_MESSAGE_IN:
+		nsp_dataphase_bypass(tmpSC);
+		DEBUG(0, " BUSPHASE_MESSAGE_IN\n");
+		if ((phase & BUSMON_REQ) == 0) {
+			goto timer_out;
+		}
+
+		tmpSC->SCp.phase = PH_MSG_IN;
+
+		/*
+		 * XXX: NSP QUIRK
+		 * NSP invoke interrupts only in the case of scsi phase changes,
+		 * therefore we should poll the scsi phase here to catch 
+		 * the next "msg in" if exists (no scsi phase changes).
+		 */
+		ret = 16;
+		len = 0;
+
+		do {
+			//DEBUG(0, " msgin loop\n");
+			/* read data */
+			data_reg = nsp_index_read(base, SCSIDATAIN);
+
+			/* assert ACK */
+			control_reg = nsp_index_read(base, SCSIBUSCTRL);
+			control_reg |= SCSI_ACK;
+			nsp_index_write(base, SCSIBUSCTRL, control_reg);
+			nsp_negate_signal(tmpSC, BUSMON_REQ, "msgin<REQ>");
+
+			nsp_data.MsgBuffer[len] = data_reg; len++;
+			DEBUG(0, " msg=0x%x\n", data_reg);
+
+			/* deassert ACK */
+			control_reg =  nsp_index_read(base, SCSIBUSCTRL);
+			control_reg &= ~SCSI_ACK;
+			nsp_index_write(base, SCSIBUSCTRL, control_reg);
+
+			/* catch a next signal */
+			ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_IN, BUSMON_REQ);
+		} while (ret > 0 && MSGBUF_SIZE > len);
+
+		nsp_data.MsgLen	   = len;
+		tmpSC->SCp.Message = nsp_data.MsgBuffer[len-1];
+
+		//DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, nsp_data.MsgLen);
+		break;
+
+	case BUSPHASE_SELECT:
+	default:
+		DEBUG(0, " BUSPHASE other\n");
+
+		break;
+	}
+
+	//DEBUG(0, __FUNCTION__ "() out\n");
+	return;	
+
+timer_out:
+	nsp_start_timer(tmpSC, 1000/102);
+	return;
+}
+
+#ifdef DBG_SHOWCOMMAND
+#include "nsp_debug.c"
+#endif	/* DBG_SHOWCOMMAND */
+
+/*====================================================================*/
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+    nsp_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+======================================================================*/
+static dev_link_t *nsp_attach(void)
+{
+	scsi_info_t  *info;
+	client_reg_t  client_reg;
+	dev_link_t   *link;
+	int	      ret, i;
+
+	DEBUG(0, __FUNCTION__ "()\n");
+
+	/* Create new SCSI device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) return NULL;
+	memset(info, 0, sizeof(*info));
+	link = &info->link;
+	link->priv = info;
+
+	/* Initialize the dev_link_t structure */
+	link->release.function	 = &nsp_release;
+	link->release.data	 = (u_long)link;
+
+	/* The io structure describes IO port mapping */
+	link->io.NumPorts1	 = 0x10;
+	link->io.Attributes1	 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.IOAddrLines	 = 10;	/* not used */
+
+	/* Interrupt setup */
+	link->irq.Attributes	 = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1	 = IRQ_INFO2_VALID    | IRQ_LEVEL_ID;
+	if (irq_list[0] == -1) {
+		link->irq.IRQInfo2 = irq_mask;
+	} else {
+		for (i = 0; i < 4; i++) {
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+		}
+	}
+	link->irq.Handler	 = &nspintr;
+
+	/* General socket configuration */
+	link->conf.Attributes	 = CONF_ENABLE_IRQ;
+	link->conf.Vcc		 = 50;
+	link->conf.IntType	 = INT_MEMORY_AND_IO;
+	link->conf.Present	 = PRESENT_OPTION;
+
+
+	/* Register with Card Services */
+	link->next               = dev_list;
+	dev_list                 = link;
+	client_reg.dev_info	 = &dev_info;
+	client_reg.Attributes	 = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask	 =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET	|
+		CS_EVENT_PM_SUSPEND	| CS_EVENT_PM_RESUME	 ;
+	client_reg.event_handler = &nsp_event;
+	client_reg.Version	 = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		nsp_detach(link);
+		return NULL;
+	}
+
+	return link;
+} /* nsp_attach */
+
+
+/*======================================================================
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.	 If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+======================================================================*/
+static void nsp_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+
+	DEBUG(0, __FUNCTION__ "(0x%p)\n", link);
+    
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) {
+		if (*linkp == link) {
+			break;
+		}
+	}
+	if (*linkp == NULL) {
+		return;
+	}
+
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG) {
+		nsp_release((u_long)link);
+		if (link->state & DEV_STALE_CONFIG) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
+
+	/* Break the link with Card Services */
+	if (link->handle) {
+		CardServices(DeregisterClient, link->handle);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+	kfree(link->priv);
+
+} /* nsp_detach */
+
+
+/*======================================================================
+    nsp_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+======================================================================*/
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+/*====================================================================*/
+
+static void nsp_config(dev_link_t *link)
+{
+	client_handle_t	  handle = link->handle;
+	scsi_info_t	 *info	 = link->priv;
+	tuple_t		  tuple;
+	cisparse_t	  parse;
+	int		  i, last_ret, last_fn;
+	u_char		  tuple_data[64];
+	config_info_t	  conf;
+	Scsi_Device	 *dev;
+	dev_node_t	**tail, *node;
+	struct Scsi_Host *host;
+
+	DEBUG(0, __FUNCTION__ "() in\n");
+
+	tuple.DesiredTuple    = CISTPL_CONFIG;
+	tuple.Attributes      = 0;
+	tuple.TupleData	      = tuple_data;
+	tuple.TupleDataMax    = sizeof(tuple_data);
+	tuple.TupleOffset     = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData,	handle, &tuple);
+	CS_CHECK(ParseTuple,	handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present    = parse.config.rmask[0];
+
+	/* Configure card */
+	driver_template.module = &__this_module;
+	link->state	      |= DEV_CONFIG;
+
+	/* Look up the current Vcc */
+	CS_CHECK(GetConfigurationInfo, handle, &conf);
+	link->conf.Vcc = conf.Vcc;
+
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	while (1) {
+		CFG_CHECK(GetTupleData, handle, &tuple);
+		CFG_CHECK(ParseTuple,	handle, &tuple, &parse);
+		link->conf.ConfigIndex = parse.cftable_entry.index;
+		link->io.BasePort1     = parse.cftable_entry.io.win[0].base;
+		i = CardServices(RequestIO, handle, &link->io);
+		if (i == CS_SUCCESS) {
+			break;
+		}
+	next_entry:
+		DEBUG(0, __FUNCTION__ " next\n");
+		CS_CHECK(GetNextTuple, handle, &tuple);
+	}
+
+	CS_CHECK(RequestIRQ,	       handle, &link->irq);
+	CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+	/* A bad hack... */
+	release_region(link->io.BasePort1, link->io.NumPorts1);
+
+	/* Set port and IRQ */
+	nsp_data.BaseAddress = link->io.BasePort1;
+	nsp_data.NumAddress  = link->io.NumPorts1;
+	nsp_data.IrqNumber   = link->irq.AssignedIRQ;
+
+	DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n",
+	      nsp_data.BaseAddress, nsp_data.NumAddress, nsp_data.IrqNumber);
+
+	if(nsphw_init() == FALSE) {
+		goto cs_failed;
+	}
+
+	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+	DEBUG(0, "GET_SCSI_INFO\n");
+	tail = &link->dev;
+	info->ndev = 0;
+	for (host = scsi_hostlist; host != NULL; host = host->next) {
+		if (host->hostt == &driver_template) {
+			for (dev = host->host_queue; dev != NULL; dev = dev->next) {
+				u_long arg[2], id;
+				kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+				id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+					((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+				node = &info->node[info->ndev];
+				node->minor = 0;
+				switch (dev->type) {
+				case TYPE_TAPE:
+					node->major = SCSI_TAPE_MAJOR;
+					sprintf(node->dev_name, "st#%04lx", id);
+					break;
+				case TYPE_DISK:
+				case TYPE_MOD:
+					node->major = SCSI_DISK0_MAJOR;
+					sprintf(node->dev_name, "sd#%04lx", id);
+					break;
+				case TYPE_ROM:
+				case TYPE_WORM:
+					node->major = SCSI_CDROM_MAJOR;
+					sprintf(node->dev_name, "sr#%04lx", id);
+					break;
+				default:
+					node->major = SCSI_GENERIC_MAJOR;
+					sprintf(node->dev_name, "sg#%04lx", id);
+					break;
+				}
+				*tail = node; tail = &node->next;
+				info->ndev++;
+				info->host = dev->host;
+			}
+		}
+	}
+	*tail = NULL;
+	if (info->ndev == 0) {
+		printk(KERN_INFO "nsp_cs: no SCSI devices found\n");
+	}
+
+	/* Finally, report what we've done */
+	printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d",
+	       link->conf.ConfigIndex,
+	       link->conf.Vcc/10, link->conf.Vcc%10);
+	if (link->conf.Vpp1) {
+		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	}
+	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+		printk(", irq %d", link->irq.AssignedIRQ);
+	}
+	if (link->io.NumPorts1) {
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		       link->io.BasePort1+link->io.NumPorts1-1);
+	}
+	printk("\n");
+
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	nsp_release((u_long)link);
+	return;
+
+} /* nsp_config */
+#undef CS_CHECK
+#undef CFG_CHECK
+
+/*======================================================================
+    After a card is removed, nsp_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+======================================================================*/
+static void nsp_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+
+	DEBUG(0, __FUNCTION__ "(0x%p)\n", link);
+
+	/*
+	 * If the device is currently in use, we won't release until it
+	 * is actually closed.
+	 */
+	if (link->open) {
+		DEBUG(1, "nsp_cs: release postponed, '%s' still open\n",
+		      link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	/* Unlink the device chain */
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+	link->dev = NULL;
+
+	if (link->win) {
+		CardServices(ReleaseWindow, link->win);
+	}
+	CardServices(ReleaseConfiguration,  link->handle);
+	if (link->io.NumPorts1) {
+		CardServices(ReleaseIO,     link->handle, &link->io);
+	}
+	if (link->irq.AssignedIRQ) {
+		CardServices(ReleaseIRQ,    link->handle, &link->irq);
+	}
+	link->state &= ~DEV_CONFIG;
+
+	if (link->state & DEV_STALE_LINK) {
+		nsp_detach(link);
+	}
+} /* nsp_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+    When a CARD_REMOVAL event is received, we immediately set a flag
+    to block future accesses to this device.  All the functions that
+    actually access the device should check this flag to make sure
+    the card is still present.
+    
+======================================================================*/
+static int nsp_event(event_t		    event,
+		     int		    priority,
+		     event_callback_args_t *args)
+{
+	dev_link_t  *link = args->client_data;
+	scsi_info_t *info = link->priv;
+
+	DEBUG(1, __FUNCTION__ "(0x%06x)\n", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		DEBUG(0, " event: remove\n");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			((scsi_info_t *)link->priv)->stop = 1;
+			mod_timer(&link->release, jiffies + HZ/20);
+		}
+		break;
+
+	case CS_EVENT_CARD_INSERTION:
+		DEBUG(0, " event: insert\n");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		info->bus    =  args->bus;
+		nsp_config(link);
+		break;
+
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		/* Mark the device as stopped, to block IO until later */
+		info->stop = 1;
+		if (link->state & DEV_CONFIG) {
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		DEBUG(0, " event: reset\n");
+		if (link->state & DEV_CONFIG) {
+			Scsi_Cmnd tmp;
+
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+			tmp.host = info->host;
+			nsp_reset(&tmp, 0);
+		}
+		info->stop = 0;
+		/* restart IO */
+		nsphw_init();
+		break;
+
+	default:
+		DEBUG(0, " event: unknown\n");
+		break;
+	}
+	DEBUG(0, __FUNCTION__ " end\n");
+	return 0;
+} /* nsp_event */
+
+/*----------------------------------------------------------------*/
+/* look for ninja3 card and init if found			  */
+/*----------------------------------------------------------------*/
+static int nsp_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+
+	DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id);
+
+#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)
+	sht->proc_dir	  = &proc_scsi_nsp; /* kernel 2.2 */
+#else
+	sht->proc_name	  = "nsp_cs";	    /* kernel 2.4 */
+#endif
+
+	sht->this_id	  = SCSI_INITIATOR_ID;
+
+	request_region(nsp_data.BaseAddress, nsp_data.NumAddress,"nsp_cs");
+	host		  = scsi_register(sht, 0);
+	host->io_port	  = nsp_data.BaseAddress;
+	host->unique_id	  = nsp_data.BaseAddress;
+	host->n_io_port	  = nsp_data.NumAddress;
+	host->irq	  = nsp_data.IrqNumber;
+	host->dma_channel = -1;
+
+	sprintf(nspinfo,
+/* Buffer size is 100 bytes */
+/*  0         1         2         3         4         5         6         7         8         9         0*/
+/*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
+   "NinjaSCSI-3/32Bi Driver version 2.0, I/O 0x%04lx-0x%04lx IRQ %2d",
+		host->io_port, host->io_port + host->n_io_port,
+		host->irq);
+	sht->name	  = nspinfo;
+
+	DEBUG(0, __FUNCTION__ " end\n");
+
+	return 1; /* detect done. */
+}
+
+
+/*----------------------------------------------------------------*/
+/* return info string						  */
+/*----------------------------------------------------------------*/
+static const char *nsp_info(struct Scsi_Host *host)
+{
+	return nspinfo;
+}
+
+static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why)
+{
+	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p why=%d\n", SCpnt, why);
+
+	return nsp_eh_bus_reset(SCpnt);
+}
+
+static int nsp_abort(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt);
+	return FAILED;
+}
+
+/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
+{
+}
+static int nsp_eh_abort(Scsi_Cmnd * cmd)
+{
+	DEBUG(0, __FUNCTION__"() SCpnt\n");
+}
+
+static nsp_eh_device_reset(Scsi_Cmnd *)
+{
+}
+*/
+static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = SCpnt->host->io_port;
+	int	     i;
+
+	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt);
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
+
+	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
+	mdelay(100); /* 100ms */
+	nsp_index_write(base, SCSIBUSCTRL, 0);
+	for(i = 0; i < 5; i++) {
+		(void) nsp_index_read(base, IRQPHASESENCE); /* dummy read */
+	}
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
+
+	return 0;
+}
+/*
+static nsp_eh_host_reset(Scsi_Cmnd *)
+{
+}*/
+
+/*======================================================================*
+ *	module entry point
+ *====================================================================*/
+static int __init nsp_init(void)
+{
+	servinfo_t serv;
+
+	DEBUG(0, __FUNCTION__ "() in\n");
+	DEBUG(0, "%s\n", version);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_DEBUG "nsp_cs: Card Services release "
+		       "does not match!\n");
+		return -1;
+	}
+	register_pcmcia_driver(&dev_info, &nsp_attach, &nsp_detach);
+
+	DEBUG(0, __FUNCTION__ "() out\n");
+	return 0;
+}
+
+
+static void __exit nsp_cleanup(void)
+{
+	DEBUG(0, "nsp_cs: unloading\n");
+	unregister_pcmcia_driver(&dev_info);
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG) {
+			nsp_release((u_long)dev_list);
+		}
+		nsp_detach(dev_list);
+	}
+}
+
+module_init(nsp_init);
+module_exit(nsp_cleanup);
+
+/*
+ *
+ *
+ */
+
+/* end */
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.h linux/drivers/scsi/pcmcia/nsp_cs.h
--- v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/nsp_cs.h	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,302 @@
+/*=======================================================/
+  Header file for nsp_cs.c
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+    Ver.1.0 : Cut unused lines.
+    Ver 0.1 : Initial version.
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License.
+
+=========================================================*/
+
+/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */
+
+#ifndef  __nsp_cs__
+#define  __nsp_cs__
+
+/* for debugging */
+/*
+#define DBG
+#define DBG_PRINT
+#define DBG_SHOWCOMMAND
+#define PCMCIA_DEBUG 9
+*/
+
+/*
+#define static
+#define inline
+*/
+
+/************************************
+ * Some useful macros...
+ */
+#define Number(arr) ((int) (sizeof(arr) / sizeof(arr[0])))
+#define BIT(x)      (1<<(x))
+#define MIN(a,b)    ((a) > (b) ? (b) : (a))
+
+/* SCSI initiator must be 7 */
+#define SCSI_INITIATOR_ID  7
+
+/* base register */
+#define	IRQCONTROL	0x00
+#  define IRQCONTROL_RESELECT_CLEAR     BIT(0)
+#  define IRQCONTROL_PHASE_CHANGE_CLEAR BIT(1)
+#  define IRQCONTROL_TIMER_CLEAR        BIT(2)
+#  define IRQCONTROL_FIFO_CLEAR         BIT(3)
+#  define IRQCONTROL_ALLMASK            0xff
+#  define IRQCONTROL_ALLCLEAR           0x0f
+#  define IRQCONTROL_IRQDISABLE         0xf0
+
+#define	IRQSTATUS	0x00
+#  define IRQSTATUS_SCSI  BIT(0)
+#  define IRQSTATUS_TIMER BIT(2)
+#  define IRQSTATUS_FIFO  BIT(3)
+#  define IRQSTATUS_MASK  0x0f
+
+#define	IFSELECT	0x01
+#  define IF_IFSEL    BIT(0)
+#  define IF_REGSEL   BIT(2)
+
+#define	FIFOSTATUS	0x01
+#  define FIFOSTATUS_CHIP_REVISION 0x0f
+#  define FIFOSTATUS_CHIP_ID       0x70
+#  define FIFOSTATUS_FULL_EMPTY    0x80
+
+#define	INDEXREG	0x02
+#define	DATAREG		0x03
+#define	FIFODATA	0x04
+#define	FIFODATA1	0x05
+#define	FIFODATA2	0x06
+#define	FIFODATA3	0x07
+
+/* indexed register */
+#define EXTBUSCTRL	0x10
+
+#define CLOCKDIV	0x11
+#  define CLOCK_40M 0x02
+#  define CLOCK_20M 0x01
+
+#define TERMPWRCTRL	0x13
+#  define POWER_ON BIT(0)
+
+#define SCSIIRQMODE	0x15
+#  define SCSI_PHASE_CHANGE_EI BIT(0)
+#  define RESELECT_EI          BIT(4)
+#  define FIFO_IRQ_EI          BIT(5)
+#  define SCSI_RESET_IRQ_EI    BIT(6)
+
+#define IRQPHASESENCE	0x16
+#  define LATCHED_MSG      BIT(0)
+#  define LATCHED_IO       BIT(1)
+#  define LATCHED_CD       BIT(2)
+#  define LATCHED_BUS_FREE BIT(3)
+#  define PHASE_CHANGE_IRQ BIT(4)
+#  define RESELECT_IRQ     BIT(5)
+#  define FIFO_IRQ         BIT(6)
+#  define SCSI_RESET_IRQ   BIT(7)
+
+#define TIMERCOUNT	0x17
+
+#define SCSIBUSCTRL	0x18
+#  define SCSI_SEL         BIT(0)
+#  define SCSI_RST         BIT(1)
+#  define SCSI_DATAOUT_ENB BIT(2)
+#  define SCSI_ATN         BIT(3)
+#  define SCSI_ACK         BIT(4)
+#  define SCSI_BSY         BIT(5)
+#  define AUTODIRECTION    BIT(6)
+#  define ACKENB           BIT(7)
+
+#define SCSIBUSMON	0x19
+
+#define SETARBIT	0x1A
+#  define ARBIT_GO         BIT(0)
+#  define ARBIT_FLAG_CLEAR BIT(1)
+
+#define ARBITSTATUS	0x1A
+/*#  define ARBIT_GO        BIT(0)*/
+#  define ARBIT_WIN        BIT(1)
+#  define ARBIT_FAIL       BIT(2)
+#  define RESELECT_FLAG    BIT(3)
+
+#define PARITYCTRL	0x1B  /* W */
+#define PARITYSTATUS	0x1B  /* R */
+
+#define COMMANDCTRL	0x1C  /* W */
+#  define CLEAR_COMMAND_POINTER BIT(0)
+#  define AUTO_COMMAND_GO       BIT(1)
+
+#define RESELECTID	0x1C  /* R */
+#define COMMANDDATA	0x1D
+
+#define POINTERCLR	0x1E  /* W */
+#  define POINTER_CLEAR      BIT(0)
+#  define ACK_COUNTER_CLEAR  BIT(1)
+#  define REQ_COUNTER_CLEAR  BIT(2)
+#  define HOST_COUNTER_CLEAR BIT(3)
+#  define READ_SOURCE        0x30
+
+#define TRANSFERCOUNT	0x1E  /* R */
+
+#define TRANSFERMODE	0x20
+#   define MODE_MEM8   BIT(0)
+#   define MODE_MEM32  BIT(1)
+#   define MODE_ADR24  BIT(2)
+#   define MODE_ADR32  BIT(3)
+#   define MODE_IO8    BIT(4)
+#   define MODE_IO32   BIT(5)
+#   define TRANSFER_GO BIT(6)
+#   define BRAIND      BIT(7)
+
+#define SYNCREG		0x21
+#  define SYNCREG_OFFSET_MASK  0x0f
+#  define SYNCREG_PERIOD_MASK  0xf0
+#  define SYNCREG_PERIOD_SHIFT 4
+
+#define SCSIDATALATCH	0x22
+#define SCSIDATAIN	0x22
+#define SCSIDATAWITHACK	0x23
+#define SCAMCONTROL	0x24
+#define SCAMSTATUS	0x24
+#define SCAMDATA	0x25
+
+#define OTHERCONTROL	0x26
+#  define TPL_ROM_WRITE_EN BIT(0)
+#  define TPWR_OUT         BIT(1)
+#  define TPWR_SENSE       BIT(2)
+#  define RA8_CONTROL      BIT(3)
+
+#define ACKWIDTH	0x27
+#define CLRTESTPNT	0x28
+#define ACKCNTLD	0x29
+#define REQCNTLD	0x2A
+#define HSTCNTLD	0x2B
+#define CHECKSUM	0x2C
+
+/*
+ * Input status bit definitions.
+ */
+#define S_ATN		0x80	/**/
+#define S_SELECT	0x40	/**/
+#define S_REQUEST	0x20    /* Request line from SCSI bus*/
+#define S_ACK		0x10    /* Acknowlege line from SCSI bus*/
+#define S_BUSY		0x08    /* Busy line from SCSI bus*/
+#define S_CD		0x04    /* Command/Data line from SCSI bus*/
+#define S_IO		0x02    /* Input/Output line from SCSI bus*/
+#define S_MESSAGE	0x01    /* Message line from SCSI bus*/
+
+/*
+ * Useful Bus Monitor status combinations.
+ */
+#define BUSMON_SEL         S_SELECT
+#define BUSMON_BSY         S_BUSY
+#define BUSMON_REQ         S_REQUEST
+#define BUSMON_IO          S_IO
+#define BUSMON_ACK         S_ACK
+#define BUSMON_BUS_FREE    0
+#define BUSMON_COMMAND     ( S_BUSY | S_CD | S_REQUEST )
+#define BUSMON_MESSAGE_IN  ( S_BUSY | S_MESSAGE | S_IO | S_CD | S_REQUEST )
+#define BUSMON_MESSAGE_OUT ( S_BUSY | S_MESSAGE | S_CD | S_REQUEST )
+#define BUSMON_DATA_IN     ( S_BUSY | S_IO | S_REQUEST )
+#define BUSMON_DATA_OUT    ( S_BUSY | S_REQUEST )
+#define BUSMON_STATUS      ( S_BUSY | S_IO | S_CD | S_REQUEST )
+#define BUSMON_RESELECT    ( S_SELECT | S_IO )
+#define BUSMON_PHASE_MASK  ( S_SELECT | S_CD | S_MESSAGE | S_IO )
+
+#define BUSPHASE_COMMAND     ( BUSMON_COMMAND     & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_IN  ( BUSMON_MESSAGE_IN  & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_IN     ( BUSMON_DATA_IN     & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_OUT    ( BUSMON_DATA_OUT    & BUSMON_PHASE_MASK )
+#define BUSPHASE_STATUS      ( BUSMON_STATUS      & BUSMON_PHASE_MASK )
+#define BUSPHASE_SELECT      ( S_SELECT | S_IO )
+
+/* synchronous transfer negotiation data */
+typedef struct _sync_data {
+	unsigned int SyncNegotiation;
+#define SYNC_NOT_YET 0
+#define SYNC_OK      1
+#define SYNC_NG      2
+
+	unsigned int  SyncPeriod;
+	unsigned int  SyncOffset;
+	unsigned char SyncRegister;
+	unsigned char AckWidth;
+} sync_data;
+
+typedef struct _nsp_data {
+	unsigned int  BaseAddress;
+	unsigned int  NumAddress;
+	unsigned int  IrqNumber;
+
+	unsigned char ScsiClockDiv;
+
+	unsigned char TransferMode;
+
+	int           TimerCount;
+	int           SelectionTimeOut;
+	Scsi_Cmnd    *CurrentSC;
+
+	int           FifoCount;
+#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE)
+	int           Residual;
+#define RESID nsp_data.Residual
+#else
+#define RESID SCpnt->resid
+#endif
+
+#define MSGBUF_SIZE 20
+	unsigned char MsgBuffer[MSGBUF_SIZE];
+	int MsgLen;
+
+#define N_TARGET 8
+#define N_LUN    8
+	sync_data     Sync[N_TARGET][N_LUN];
+} nsp_hw_data;
+
+
+static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt);
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time);
+
+static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt);
+
+static int nsp_fifo_count(Scsi_Cmnd *SCpnt);
+static void nsp_pio_read(Scsi_Cmnd *SCpnt);
+static int nsp_nexus(Scsi_Cmnd *SCpnt);
+
+#ifdef PCMCIA_DEBUG
+# ifdef DBG_SHOWCOMMAND
+static void show_command(Scsi_Cmnd *ptr);
+static void show_phase(Scsi_Cmnd *SCpnt);
+static void show_busphase(unsigned char stat);
+# endif /* DBG_SHOWCOMMAND */
+#endif
+
+/*
+ * SCSI phase
+ */
+enum _scsi_phase {
+	PH_UNDETERMINED,
+	PH_ARBSTART,
+	PH_SELSTART,
+	PH_SELECTED,
+	PH_COMMAND,
+	PH_DATA,
+	PH_STATUS,
+	PH_MSG_IN,
+	PH_MSG_OUT,
+	PH_DISCONNECT,
+	PH_RESELECT
+};
+
+enum _data_in_out {
+	IO_UNKNOWN,
+	IO_IN,
+	IO_OUT
+};
+
+
+#define NSP_SELTIMEOUT 200
+
+#endif  /*__nsp_cs__*/
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_debug.c linux/drivers/scsi/pcmcia/nsp_debug.c
--- v2.4.6/linux/drivers/scsi/pcmcia/nsp_debug.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/nsp_debug.c	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,195 @@
+/*========================================================================
+    Debug routines for nsp_cs
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License.
+=========================================================================*/
+
+/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */
+
+/*
+ * Show the command data of a command
+ */
+static const char unknown[] = "UNKNOWN";
+
+static const char * group_0_commands[] = {
+/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
+/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
+/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
+/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
+/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
+/* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
+};
+
+
+static const char *group_1_commands[] = {
+/* 20-22 */  unknown, unknown, unknown,
+/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)",
+/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown,
+/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
+/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer",
+/* 3d-3f */ "Update Block", "Read Long",  "Write Long",
+};
+
+
+static const char *group_2_commands[] = {
+/* 40-41 */ "Change Definition", "Write Same", 
+/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", 
+/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown,
+/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
+/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
+/* 5c-5f */ unknown, unknown, unknown,
+};
+
+#define group(opcode) (((opcode) >> 5) & 7)
+
+#define RESERVED_GROUP  0
+#define VENDOR_GROUP    1
+#define NOTEXT_GROUP    2
+
+static const char **commands[] = {
+    group_0_commands, group_1_commands, group_2_commands, 
+    (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
+    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    (const char **) VENDOR_GROUP
+};
+
+static const char reserved[] = "RESERVED";
+static const char vendor[] = "VENDOR SPECIFIC";
+
+static void print_opcodek(unsigned char opcode)
+{
+	const char **table = commands[ group(opcode) ];
+
+	switch ((unsigned long) table) {
+	case RESERVED_GROUP:
+		printk("%s[%02x] ", reserved, opcode); 
+		break;
+	case NOTEXT_GROUP:
+		printk("%s(notext)[%02x] ", unknown, opcode); 
+		break;
+	case VENDOR_GROUP:
+		printk("%s[%02x] ", vendor, opcode); 
+		break;
+	default:
+		if (table[opcode & 0x1f] != unknown)
+			printk("%s[%02x] ", table[opcode & 0x1f], opcode);
+		else
+			printk("%s[%02x] ", unknown, opcode);
+		break;
+	}
+}
+
+void print_commandk (unsigned char *command)
+{
+	int i,s;
+	printk(KERN_DEBUG);
+	print_opcodek(command[0]);
+	/*printk(KERN_DEBUG __FUNCTION__ " ");*/
+	for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) {
+		printk("%02x ", command[i]);
+	}
+	switch (COMMAND_SIZE(command[0])) {
+	case 6:
+		printk("LBA=%d len=%d",
+		       (((unsigned int)command[1] & 0x0f) << 16) |
+		       ( (unsigned int)command[2]         <<  8) |
+		       ( (unsigned int)command[3]              ),
+		       (unsigned int)command[4]
+			);
+		break;
+	case 10:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[7] <<  8) |
+		       ((unsigned int)command[8]      )
+		       );
+		break;
+	case 12:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[6] << 24) |
+		       ((unsigned int)command[7] << 16) |
+		       ((unsigned int)command[8] <<  8) |
+		       ((unsigned int)command[9]      )
+		       );
+		break;
+	default:
+		break;
+	}
+	printk("\n");
+}
+
+static void show_command(Scsi_Cmnd *ptr)
+{
+	print_commandk(ptr->cmnd);
+}
+
+static void show_phase(Scsi_Cmnd *SCpnt)
+{
+	int i = SCpnt->SCp.phase;
+
+	char *ph[] = {
+		"PH_UNDETERMINED",
+		"PH_ARBSTART",
+		"PH_SELSTART",
+		"PH_SELECTED",
+		"PH_COMMAND",
+		"PH_DATA",
+		"PH_STATUS",
+		"PH_MSG_IN",
+		"PH_MSG_OUT",
+		"PH_DISCONNECT",
+		"PH_RESELECT"
+	};
+
+	if ( i < PH_UNDETERMINED || i > PH_RESELECT ) {
+		printk(KERN_DEBUG "scsi phase: unknown(%d)\n", i);
+		return;
+	}
+
+	printk(KERN_DEBUG "scsi phase: %s\n", ph[i]);
+
+	return;
+}
+
+static void show_busphase(unsigned char stat)
+{
+	switch(stat) {
+	case BUSPHASE_COMMAND:
+		printk(KERN_DEBUG "BUSPHASE_COMMAND\n");
+		break;
+	case BUSPHASE_MESSAGE_IN:
+		printk(KERN_DEBUG "BUSPHASE_MESSAGE_IN\n");
+		break;
+	case BUSPHASE_MESSAGE_OUT:
+		printk(KERN_DEBUG "BUSPHASE_MESSAGE_OUT\n");
+		break;
+	case BUSPHASE_DATA_IN:
+		printk(KERN_DEBUG "BUSPHASE_DATA_IN\n");
+		break;
+	case BUSPHASE_DATA_OUT:
+		printk(KERN_DEBUG "BUSPHASE_DATA_OUT\n");
+		break;
+	case BUSPHASE_STATUS:
+		printk(KERN_DEBUG "BUSPHASE_STATUS\n");
+		break;
+	case BUSPHASE_SELECT:
+		printk(KERN_DEBUG "BUSPHASE_SELECT\n");
+		break;
+	default:
+		printk(KERN_DEBUG "BUSPHASE_other\n");
+		break;
+	}
+}
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_io.h linux/drivers/scsi/pcmcia/nsp_io.h
--- v2.4.6/linux/drivers/scsi/pcmcia/nsp_io.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/nsp_io.h	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,176 @@
+/*
+  NinjaSCSI I/O funtions 
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ 
+  This software may be used and distributed according to the terms of
+  the GNU General Public License.
+
+  */
+
+/* $Id: nsp_io.h,v 1.8 2001/01/30 05:16:02 elca Exp $ */
+
+#ifndef __NSP_IO_H__
+#define __NSP_IO_H__
+
+static inline          void nsp_write(unsigned int base,
+				      unsigned int index,
+				      unsigned char val);
+static inline unsigned char nsp_read(unsigned int base,
+				     unsigned int index);
+static inline          void nsp_index_write(unsigned int BaseAddr,
+					    unsigned int Register,
+					    unsigned char Value);
+static inline unsigned char nsp_index_read(unsigned int BaseAddr,
+					   unsigned int Register);
+
+/*******************************************************************
+ * Basic IO
+ */
+
+static inline void nsp_write(unsigned int  base,
+			     unsigned int  index,
+			     unsigned char val)
+{
+	outb(val, (base + index));
+}
+
+static inline unsigned char nsp_read(unsigned int base,
+				     unsigned int index)
+{
+	return inb(base + index);
+}
+
+
+/**********************************************************************
+ * Indexed IO
+ */
+static inline unsigned char nsp_index_read(unsigned int BaseAddr,
+					   unsigned int Register)
+{
+	outb(Register, BaseAddr + INDEXREG);
+	return inb(BaseAddr + DATAREG);
+}
+
+static inline void nsp_index_write(unsigned int  BaseAddr,
+				   unsigned int  Register,
+				   unsigned char Value)
+{
+	outb(Register, BaseAddr + INDEXREG);
+	outb(Value, BaseAddr + DATAREG);
+}
+
+/*********************************************************************
+ * fifo func
+ */
+
+/* read 8 bit FIFO */
+static inline void nsp_multi_read_1(unsigned int   BaseAddr,
+				    unsigned int   Register,
+				    void          *buf,
+				    unsigned long  count)
+{
+	insb(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo8_read(unsigned int   base,
+				  void          *buf,
+				  unsigned long  count)
+{
+	//DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx\n", buf, count);
+	nsp_multi_read_1(base, FIFODATA, buf, count);
+}
+
+/*--------------------------------------------------------------*/
+
+/* read 16 bit FIFO */
+static inline void nsp_multi_read_2(unsigned int   BaseAddr,
+				    unsigned int   Register,
+				    void          *buf,
+				    unsigned long  count)
+{
+	insw(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo16_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*2\n", buf, count);
+	nsp_multi_read_2(base, FIFODATA, buf, count);
+}
+
+/*--------------------------------------------------------------*/
+
+/* read 32bit FIFO */
+static inline void nsp_multi_read_4(unsigned int   BaseAddr,
+				    unsigned int   Register,
+				    void          *buf,
+				    unsigned long  count)
+{
+	insl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo32_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count);
+	nsp_multi_read_4(base, FIFODATA, buf, count);
+}
+
+/*----------------------------------------------------------*/
+
+/* write 8bit FIFO */
+static inline void nsp_multi_write_1(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	outsb(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo8_write(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	nsp_multi_write_1(base, FIFODATA, buf, count);
+}
+
+/*---------------------------------------------------------*/
+
+/* write 16bit FIFO */
+static inline void nsp_multi_write_2(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	outsw(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo16_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp_multi_write_2(base, FIFODATA, buf, count);
+}
+
+/*---------------------------------------------------------*/
+
+/* write 32bit FIFO */
+static inline void nsp_multi_write_4(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	outsl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo32_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp_multi_write_4(base, FIFODATA, buf, count);
+}
+
+#endif
+/* end */
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.4.6/linux/drivers/scsi/qlogicisp.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/qlogicisp.c	Thu Jul  5 11:28:17 2001
@@ -704,6 +704,7 @@
 		}
 
 		host->this_id = hostdata->host_param.initiator_scsi_id;
+		host->max_sectors = 64;
 
 		if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
 				"qlogicisp", host))
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.4.6/linux/drivers/scsi/qlogicpti.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/qlogicpti.c	Thu Jul  5 11:28:17 2001
@@ -737,6 +737,7 @@
 			prom_getintdefault(qpti->sdev->bus->prom_node,
 					   "scsi-initiator-id", 7);
 	qpti->qhost->this_id = qpti->scsi_id;
+	qpti->qhost->max_sectors = 64;
 
 	printk("SCSI ID %d ", qpti->scsi_id);
 }
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.4.6/linux/drivers/scsi/scsi.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/scsi.c	Thu Jul  5 11:28:17 2001
@@ -53,6 +53,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #define __KERNEL_SYSCALLS__
 
@@ -1098,7 +1099,7 @@
 	 * the response.  We treat it as if the command never finished.
 	 *
 	 * Since serial_number is now 0, the error handler cound detect this
-	 * situation and avoid to call the the low level driver abort routine.
+	 * situation and avoid to call the low level driver abort routine.
 	 * (DB)
          *
          * FIXME(eric) - I believe that this test is now redundant, due to
@@ -1373,7 +1374,7 @@
 }
 
 static int scsi_register_host(Scsi_Host_Template *);
-static void scsi_unregister_host(Scsi_Host_Template *);
+static int scsi_unregister_host(Scsi_Host_Template *);
 
 /*
  * Function:    scsi_release_commandblocks()
@@ -1569,12 +1570,17 @@
 
 	if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
-	copy_from_user(buffer, buf, length);
+	if(copy_from_user(buffer, buf, length))
+	{
+		err =-EFAULT;
+		goto out;
+	}
 
 	err = -EINVAL;
+
 	if (length < PAGE_SIZE)
-		buffer[length] ='\0';
-	else if (buffer[length])
+		buffer[length] = '\0';
+	else if (buffer[PAGE_SIZE-1])
 		goto out;
 
 	if (length < 11 || strncmp("scsi", buffer, 4))
@@ -1821,6 +1827,11 @@
 		return 1;	/* Must be already loaded, or
 				 * no detect routine available
 				 */
+
+	/* If max_sectors isn't set, default to max */
+	if (!tpnt->max_sectors)
+		tpnt->max_sectors = MAX_SECTORS;
+
 	pcount = next_scsi_host;
 
 	/* The detect routine must carefully spinunlock/spinlock if 
@@ -1965,14 +1976,8 @@
 /*
  * Similarly, this entry point should be called by a loadable module if it
  * is trying to remove a low level scsi driver from the system.
- *
- * Note - there is a fatal flaw in the deregister module function.
- * There is no way to return a code that says 'I cannot be unloaded now'.
- * The system relies entirely upon usage counts that are maintained,
- * and the assumption is that if the usage count is 0, then the module
- * can be unloaded.
  */
-static void scsi_unregister_host(Scsi_Host_Template * tpnt)
+static int scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
 	int online_status;
 	int pcount0, pcount;
@@ -1984,6 +1989,9 @@
 	struct Scsi_Host *shpnt;
 	char name[10];	/* host_no>=10^9? I don't think so. */
 
+	/* get the big kernel lock, so we don't race with open() */
+	lock_kernel();
+
 	/*
 	 * First verify that this host adapter is completely free with no pending
 	 * commands 
@@ -1994,7 +2002,7 @@
 			if (SDpnt->host->hostt == tpnt
 			    && SDpnt->host->hostt->module
 			    && GET_USE_COUNT(SDpnt->host->hostt->module))
-				return;
+				goto err_out;
 			/* 
 			 * FIXME(eric) - We need to find a way to notify the
 			 * low level driver that we are shutting down - via the
@@ -2046,7 +2054,7 @@
 					}
 					SDpnt->online = online_status;
 					printk(KERN_ERR "Device busy???\n");
-					return;
+					goto err_out;
 				}
 				/*
 				 * No, this device is really free.  Mark it as such, and
@@ -2072,7 +2080,7 @@
 			/* If something still attached, punt */
 			if (SDpnt->attached) {
 				printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached);
-				return;
+				goto err_out;
 			}
 			devfs_unregister (SDpnt->de);
 		}
@@ -2180,6 +2188,13 @@
 		}
 	}
 	MOD_DEC_USE_COUNT;
+
+	unlock_kernel();
+	return 0;
+
+err_out:
+	unlock_kernel();
+	return -1;
 }
 
 static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
@@ -2261,12 +2276,13 @@
 	struct Scsi_Host *shpnt;
 	struct Scsi_Device_Template *spnt;
 	struct Scsi_Device_Template *prev_spnt;
-
+	
+	lock_kernel();
 	/*
 	 * If we are busy, this is not going to fly.
 	 */
 	if (GET_USE_COUNT(tpnt->module) != 0)
-		return 0;
+		goto error_out;
 
 	/*
 	 * Next, detach the devices from the driver.
@@ -2303,11 +2319,15 @@
 		prev_spnt->next = spnt->next;
 
 	MOD_DEC_USE_COUNT;
+	unlock_kernel();
 	/*
 	 * Final cleanup for the driver is done in the driver sources in the
 	 * cleanup function.
 	 */
 	return 0;
+error_out:
+	unlock_kernel();
+	return -1;
 }
 
 
@@ -2344,22 +2364,24 @@
 
 /* Reverse the actions taken above
  */
-void scsi_unregister_module(int module_type, void *ptr)
+int scsi_unregister_module(int module_type, void *ptr)
 {
+	int retval = 0;
+
 	switch (module_type) {
 	case MODULE_SCSI_HA:
-		scsi_unregister_host((Scsi_Host_Template *) ptr);
+		retval = scsi_unregister_host((Scsi_Host_Template *) ptr);
 		break;
 	case MODULE_SCSI_DEV:
-		scsi_unregister_device((struct Scsi_Device_Template *) ptr);
-		break;
+		retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr);
+ 		break;
 		/* The rest of these are not yet implemented. */
 	case MODULE_SCSI_CONST:
 	case MODULE_SCSI_IOCTL:
-	default:
 		break;
+	default:;
 	}
-	return;
+	return retval;
 }
 
 #ifdef CONFIG_PROC_FS
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.4.6/linux/drivers/scsi/scsi.h	Fri May 25 18:02:21 2001
+++ linux/drivers/scsi/scsi.h	Mon Jul  9 11:42:13 2001
@@ -617,6 +617,9 @@
 	unsigned remap:1;	/* support remapping  */
 	unsigned starved:1;	/* unable to process commands because
 				   host busy */
+
+	// Flag to allow revalidate to succeed in sd_open
+	int allow_revalidate;
 };
 
 
@@ -668,7 +671,7 @@
 	unsigned short sr_use_sg;	/* Number of pieces of scatter-gather */
 	unsigned short sr_sglist_len;	/* size of malloc'd scatter-gather list */
 	unsigned sr_underflow;	/* Return error if less than
-				   this amount is transfered */
+				   this amount is transferred */
 };
 
 /*
@@ -756,7 +759,7 @@
 	void *buffer;		/* Data buffer */
 
 	unsigned underflow;	/* Return error if less than
-				   this amount is transfered */
+				   this amount is transferred */
 	unsigned old_underflow;	/* save underflow here when reusing the
 				 * command for error handling */
 
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.4.6/linux/drivers/scsi/scsi_error.c	Sun Mar  4 14:30:27 2001
+++ linux/drivers/scsi/scsi_error.c	Thu Jul  5 11:28:17 2001
@@ -427,7 +427,8 @@
 	memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
 	       sizeof(generic_sense));
 
-	SCpnt->cmnd[1] = SCpnt->lun << 5;
+	if (SCpnt->device->scsi_level <= SCSI_2)
+		SCpnt->cmnd[1] = SCpnt->lun << 5;
 
 	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
 	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
@@ -496,7 +497,8 @@
 	memcpy((void *) SCpnt->cmnd, (void *) tur_command,
 	       sizeof(tur_command));
 
-	SCpnt->cmnd[1] = SCpnt->lun << 5;
+	if (SCpnt->device->scsi_level <= SCSI_2)
+		SCpnt->cmnd[1] = SCpnt->lun << 5;
 
 	/*
 	 * Zero the sense buffer.  The SCSI spec mandates that any
@@ -1175,6 +1177,14 @@
 		 */
 		if (SCpnt->device->expecting_cc_ua) {
 			SCpnt->device->expecting_cc_ua = 0;
+			return NEEDS_RETRY;
+		}
+		/*
+		 * If the device is in the process of becoming ready, we 
+		 * should retry.
+		 */
+		if ((SCpnt->sense_buffer[12] == 0x04) &&
+			(SCpnt->sense_buffer[13] == 0x01)) {
 			return NEEDS_RETRY;
 		}
 		return SUCCESS;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.4.6/linux/drivers/scsi/scsi_ioctl.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/scsi_ioctl.c	Thu Jul  5 11:28:17 2001
@@ -79,7 +79,7 @@
  * 
  * *(char *) ((int *) arg)[2] the actual command byte.   
  * 
- * Note that if more than MAX_BUF bytes are requested to be transfered,
+ * Note that if more than MAX_BUF bytes are requested to be transferred,
  * the ioctl will fail with error EINVAL.  MAX_BUF can be increased in
  * the future by increasing the size that scsi_malloc will accept.
  * 
@@ -196,8 +196,8 @@
 	Scsi_Request *SRpnt;
 	Scsi_Device *SDpnt;
 	unsigned char opcode;
-	int inlen, outlen, cmdlen;
-	int needed, buf_needed;
+	unsigned int inlen, outlen, cmdlen;
+	unsigned int needed, buf_needed;
 	int timeout, retries, result;
 	int data_direction;
 
@@ -209,8 +209,11 @@
 	if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
 		return -EFAULT;
 
-	__get_user(inlen, &sic->inlen);
-	__get_user(outlen, &sic->outlen);
+	if(__get_user(inlen, &sic->inlen))
+		return -EFAULT;
+		
+	if(__get_user(outlen, &sic->outlen))
+		return -EFAULT;
 
 	/*
 	 * We do not transfer more than MAX_BUF with this interface.
@@ -223,7 +226,8 @@
 		return -EINVAL;
 
 	cmd_in = sic->data;
-	__get_user(opcode, cmd_in);
+	if(get_user(opcode, cmd_in))
+		return -EFAULT;
 
 	needed = buf_needed = (inlen > outlen ? inlen : outlen);
 	if (buf_needed) {
@@ -254,21 +258,27 @@
 	 * Obtain the command from the user's address space.
 	 */
 	cmdlen = COMMAND_SIZE(opcode);
+	
+	result = -EFAULT;
 
 	if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
-		return -EFAULT;
+		goto error;
 
-	__copy_from_user(cmd, cmd_in, cmdlen);
+	if(__copy_from_user(cmd, cmd_in, cmdlen))
+		goto error;
 
 	/*
 	 * Obtain the data to be sent to the device (if any).
 	 */
-	__copy_from_user(buf, cmd_in + cmdlen, inlen);
+
+	if(copy_from_user(buf, cmd_in + cmdlen, inlen))
+		goto error;
 
 	/*
 	 * Set the lun field to the correct value.
 	 */
-	cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
+	if (dev->scsi_level <= SCSI_2)
+		cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
 
 	switch (opcode) {
 	case FORMAT_UNIT:
@@ -303,7 +313,8 @@
 	SRpnt = scsi_allocate_request(dev);
         if( SRpnt == NULL )
         {
-                return -EINTR;
+                result = -EINTR;
+                goto error;
         }
 
 	SRpnt->sr_data_direction = data_direction;
@@ -312,7 +323,9 @@
 	/* 
 	 * If there was an error condition, pass the info back to the user. 
 	 */
+
 	result = SRpnt->sr_result;
+
 	if (SRpnt->sr_result) {
 		int sb_len = sizeof(SRpnt->sr_sense_buffer);
 
@@ -322,12 +335,13 @@
 	} else {
 		if (copy_to_user(cmd_in, buf, outlen))
 			result = -EFAULT;
-	}
+	}	
 
 	SDpnt = SRpnt->sr_device;
 	scsi_release_request(SRpnt);
 	SRpnt = NULL;
 
+error:
 	if (buf)
 		scsi_free(buf, buf_needed);
 
@@ -379,6 +393,7 @@
 int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
 {
 	char scsi_cmd[MAX_COMMAND_SIZE];
+	char cmd_byte1;
 
 	/* No idea how this happens.... */
 	if (!dev)
@@ -393,14 +408,16 @@
 	if (!scsi_block_when_processing_errors(dev)) {
 		return -ENODEV;
 	}
+	cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
+
 	switch (cmd) {
 	case SCSI_IOCTL_GET_IDLUN:
 		if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)))
 			return -EFAULT;
 
-		__put_user(dev->id
-			 + (dev->lun << 8)
-			 + (dev->channel << 16)
+		__put_user((dev->id & 0xff)
+			 + ((dev->lun & 0xff) << 8)
+			 + ((dev->channel & 0xff) << 16)
 			 + ((dev->host->host_no & 0xff) << 24),
 			 &((Scsi_Idlun *) arg)->dev_id);
 		__put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
@@ -434,7 +451,7 @@
 		if (!dev->removable || !dev->lockable)
 			return 0;
 		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -444,14 +461,14 @@
 		if (!dev->removable || !dev->lockable)
 			return 0;
 		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
 				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
 	case SCSI_IOCTL_TEST_UNIT_READY:
 		scsi_cmd[0] = TEST_UNIT_READY;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = 0;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -459,7 +476,7 @@
 		break;
 	case SCSI_IOCTL_START_UNIT:
 		scsi_cmd[0] = START_STOP;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = 1;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
@@ -467,7 +484,7 @@
 		break;
 	case SCSI_IOCTL_STOP_UNIT:
 		scsi_cmd[0] = START_STOP;
-		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[1] = cmd_byte1;
 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 		scsi_cmd[4] = 0;
 		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.4.6/linux/drivers/scsi/scsi_lib.c	Fri May  4 15:16:28 2001
+++ linux/drivers/scsi/scsi_lib.c	Thu Jul  5 11:30:26 2001
@@ -377,12 +377,15 @@
 			nsect = bh->b_size >> 9;
 			blk_finished_io(nsect);
 			req->bh = bh->b_reqnext;
-			req->nr_sectors -= nsect;
-			req->sector += nsect;
 			bh->b_reqnext = NULL;
 			sectors -= nsect;
 			bh->b_end_io(bh, uptodate);
 			if ((bh = req->bh) != NULL) {
+				req->hard_sector += nsect;
+				req->hard_nr_sectors -= nsect;
+				req->sector += nsect;
+				req->nr_sectors -= nsect;
+
 				req->current_nr_sectors = bh->b_size >> 9;
 				if (req->nr_sectors < req->current_nr_sectors) {
 					req->nr_sectors = req->current_nr_sectors;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- v2.4.6/linux/drivers/scsi/scsi_merge.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/scsi_merge.c	Thu Jul  5 11:28:17 2001
@@ -417,6 +417,9 @@
 		max_segments = 64;
 #endif
 
+	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -473,6 +476,9 @@
 		max_segments = 64;
 #endif
 
+	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -597,6 +603,13 @@
 	Scsi_Device *SDpnt;
 	struct Scsi_Host *SHpnt;
 
+	/*
+	 * First check if the either of the requests are re-queued
+	 * requests.  Can't merge them if they are.
+	 */
+	if (req->special || next->special)
+		return 0;
+
 	SDpnt = (Scsi_Device *) q->queuedata;
 	SHpnt = SDpnt->host;
 
@@ -624,6 +637,10 @@
 		return 0;
 	}
 #endif
+
+	if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors)
+		return 0;
+
 	/*
 	 * The main question is whether the two segments at the boundaries
 	 * would be considered one or two.
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.4.6/linux/drivers/scsi/scsi_obsolete.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/scsi_obsolete.c	Thu Jul  5 11:28:17 2001
@@ -223,7 +223,8 @@
 	memset((void *) SCpnt->sense_buffer, 0,
 	       sizeof(SCpnt->sense_buffer));
 
-	SCpnt->cmnd[1] = SCpnt->lun << 5;
+	if (SCpnt->device->scsi_level <= SCSI_2)
+		SCpnt->cmnd[1] = SCpnt->lun << 5;
 	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
 
 	SCpnt->request_buffer = &SCpnt->sense_buffer;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- v2.4.6/linux/drivers/scsi/scsi_scan.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/scsi_scan.c	Thu Jul  5 11:28:17 2001
@@ -40,9 +40,13 @@
 #define BLIST_ISROM     	0x200
 
 static void print_inquiry(unsigned char *data);
-static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
-		int *sparse_lun, Scsi_Device ** SDpnt,
-			     struct Scsi_Host *shpnt, char *scsi_result);
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+		unsigned int lun, int lun0_scsi_level, 
+		unsigned int *max_scsi_dev, unsigned int *sparse_lun, 
+		Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, 
+		char *scsi_result);
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+				struct Scsi_Host *shpnt);
 
 struct dev_info {
 	const char *vendor;
@@ -135,6 +139,7 @@
 	{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
 	{"DEC","HSG80","*", BLIST_FORCELUN},
 	{"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
+	{"COMPAQ","CR3500","*", 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},
@@ -143,7 +148,11 @@
 	{"MegaRAID", "LD", "*", BLIST_FORCELUN},
 	{"DGC",  "RAID",      "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
 	{"DGC",  "DISK",      "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) 
+	{"DELL", "PV660F",   "*", BLIST_SPARSELUN},
+	{"DELL", "PV660F   PSEUDO",   "*", BLIST_SPARSELUN},
+	{"DELL", "PSEUDO DEVICE .",   "*", BLIST_SPARSELUN}, // Dell PV 530F
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN}, // Dell PV 530F
+	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
 	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
 	{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
 	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
@@ -154,29 +163,31 @@
 	{NULL, NULL, NULL}
 };
 
+#define MAX_SCSI_LUNS 0xFFFFFFFF
+
 #ifdef CONFIG_SCSI_MULTI_LUN
-static int max_scsi_luns = 8;
+static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
 #else
-static int max_scsi_luns = 1;
+static unsigned int max_scsi_luns = 1;
 #endif
 
 #ifdef MODULE
 
 MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
+MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
 
 #else
 
 static int __init scsi_luns_setup(char *str)
 {
-	int tmp;
+	unsigned int tmp;
 
 	if (get_option(&str, &tmp) == 1) {
 		max_scsi_luns = tmp;
 		return 1;
 	} else {
 		printk("scsi_luns_setup : usage max_scsi_luns=n "
-		       "(n should be between 1 and 8)\n");
+		       "(n should be between 1 and 2^32-1)\n");
 		return 0;
 	}
 }
@@ -264,14 +275,15 @@
 		       uint hlun)
 {
 	uint channel;
-	int dev;
-	int lun;
-	int max_dev_lun;
+	unsigned int dev;
+	unsigned int lun;
+	unsigned int max_dev_lun;
 	unsigned char *scsi_result;
 	unsigned char scsi_result0[256];
 	Scsi_Device *SDpnt;
 	Scsi_Device *SDtail;
-	int sparse_lun;
+	unsigned int sparse_lun;
+	int lun0_sl;
 
 	scsi_result = NULL;
 
@@ -343,8 +355,12 @@
 		lun = hlun;
 		if (lun >= shpnt->max_lun)
 			goto leave;
-		scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
-				  &SDpnt, shpnt, scsi_result);
+		if ((0 == lun) || (lun > 7))
+			lun0_sl = SCSI_3; /* actually don't care for 0 == lun */
+		else
+			lun0_sl = find_lun0_scsi_level(channel, dev, shpnt);
+		scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, 
+				  &sparse_lun, &SDpnt, shpnt, scsi_result);
 		if (SDpnt != oldSDpnt) {
 
 			/* it could happen the blockdevice hasn't yet been inited */
@@ -400,12 +416,14 @@
 					max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
 					 max_scsi_luns : shpnt->max_lun);
 					sparse_lun = 0;
-					for (lun = 0; lun < max_dev_lun; ++lun) {
-						if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
-								       &sparse_lun, &SDpnt, shpnt,
-							     scsi_result)
+					for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) {
+						if (!scan_scsis_single(channel, order_dev, lun, lun0_sl,
+							 	       &max_dev_lun, &sparse_lun, &SDpnt, shpnt,
+								       scsi_result)
 						    && !sparse_lun)
 							break;	/* break means don't probe further for luns!=0 */
+						if (SDpnt && (0 == lun))
+							lun0_sl = SDpnt->scsi_level;
 					}	/* for lun ends */
 				}	/* if this_id != id ends */
 			}	/* for dev ends */
@@ -461,9 +479,11 @@
  * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
  * Global variables used : scsi_devices(linked list)
  */
-static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
-	       int *sparse_lun, Scsi_Device ** SDpnt2, 
-		      struct Scsi_Host *shpnt, char *scsi_result)
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+		unsigned int lun, int lun0_scsi_level,
+		unsigned int *max_dev_lun, unsigned int *sparse_lun, 
+		Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, 
+		char *scsi_result)
 {
 	char devname[64];
 	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -509,7 +529,10 @@
 	 * Build an INQUIRY command block.
 	 */
 	scsi_cmd[0] = INQUIRY;
-	scsi_cmd[1] = (lun << 5) & 0xe0;
+	if ((lun > 0) && (lun0_scsi_level <= SCSI_2))
+		scsi_cmd[1] = (lun << 5) & 0xe0;
+	else	
+		scsi_cmd[1] = 0;	/* SCSI_3 and higher, don't touch */
 	scsi_cmd[2] = 0;
 	scsi_cmd[3] = 0;
 	scsi_cmd[4] = 255;
@@ -677,7 +700,9 @@
 		printk("Unlocked floptical drive.\n");
 		SDpnt->lockable = 0;
 		scsi_cmd[0] = MODE_SENSE;
-		scsi_cmd[1] = (lun << 5) & 0xe0;
+		if (shpnt->max_lun <= 8)
+			scsi_cmd[1] = (lun << 5) & 0xe0;
+		else	scsi_cmd[1] = 0;	/* any other idea? */
 		scsi_cmd[2] = 0x2e;
 		scsi_cmd[3] = 0;
 		scsi_cmd[4] = 0x2a;
@@ -760,7 +785,19 @@
 	 * other settings, and scan all of them.
 	 */
 	if (bflags & BLIST_SPARSELUN) {
-		*max_dev_lun = 8;
+		/*
+		 * Scanning MAX_SCSI_LUNS units would be a bad idea.
+		 * Any better idea?
+		 * I think we need REPORT LUNS in future to avoid scanning
+		 * of unused LUNs. But, that is another item.
+		 *
+		 * FIXME(eric) - perhaps this should be a kernel configurable?
+		 */
+		if (*max_dev_lun < shpnt->max_lun)
+			*max_dev_lun = shpnt->max_lun;
+		else 	if ((max_scsi_luns >> 1) >= *max_dev_lun)
+				*max_dev_lun += shpnt->max_lun;
+			else	*max_dev_lun = max_scsi_luns;
 		*sparse_lun = 1;
 		return 1;
 	}
@@ -769,7 +806,17 @@
 	 * settings, and scan all of them.
 	 */
 	if (bflags & BLIST_FORCELUN) {
-		*max_dev_lun = 8;
+		/* 
+		 * Scanning MAX_SCSI_LUNS units would be a bad idea.
+		 * Any better idea?
+		 * I think we need REPORT LUNS in future to avoid scanning
+		 * of unused LUNs. But, that is another item.
+		 */
+		if (*max_dev_lun < shpnt->max_lun)
+			*max_dev_lun = shpnt->max_lun;
+		else 	if ((max_scsi_luns >> 1) >= *max_dev_lun)
+				*max_dev_lun += shpnt->max_lun;
+			else	*max_dev_lun = max_scsi_luns;
 		return 1;
 	}
 	/*
@@ -793,3 +840,23 @@
 	return 1;
 }
 
+/*
+ * The worker for scan_scsis.
+ * Returns the scsi_level of lun0 on this host, channel and dev (if already
+ * known), otherwise returns SCSI_2.
+ */
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+				struct Scsi_Host *shpnt)
+{
+	int res = SCSI_2;
+	Scsi_Device *SDpnt;
+
+	for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+	{
+		if ((0 == SDpnt->lun) && (dev == SDpnt->id) &&
+		    (channel == SDpnt->channel))
+			return (int)SDpnt->scsi_level;
+	}
+	/* haven't found lun0, should send INQUIRY but take easy route */
+	return res;
+}
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.4.6/linux/drivers/scsi/sd.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/scsi/sd.c	Thu Jul  5 11:28:17 2001
@@ -22,6 +22,12 @@
  *	
  *	 Modified by Torben Mathiasen tmm@image.dk
  *       Resource allocation fixes in sd_init and cleanups.
+ *	
+ *	 Modified by Alex Davis <letmein@erols.com>
+ *       Fix problem where partition info not being read in sd_open.
+ *	
+ *	 Modified by Alex Davis <letmein@erols.com>
+ *       Fix problem where removable media could be ejected after sd_open.
  */
 
 #include <linux/config.h>
@@ -372,7 +378,8 @@
 		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
 				 this_count, SCpnt->request.nr_sectors));
 
-	SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+			 ((SCpnt->lun << 5) & 0xe0) : 0;
 
 	if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) {
 		if (this_count > 0xffff)
@@ -424,7 +431,7 @@
 
 static int sd_open(struct inode *inode, struct file *filp)
 {
-	int target;
+	int target, retval = -ENXIO;
 	Scsi_Device * SDev;
 	target = DEVICE_NR(inode->i_rdev);
 
@@ -448,24 +455,40 @@
 
 	while (rscsi_disks[target].device->busy)
 		barrier();
+	/*
+	 * The following code can sleep.
+	 * Module unloading must be prevented
+	 */
+	SDev = rscsi_disks[target].device;
+	if (SDev->host->hostt->module)
+		__MOD_INC_USE_COUNT(SDev->host->hostt->module);
+	if (sd_template.module)
+		__MOD_INC_USE_COUNT(sd_template.module);
+	SDev->access_count++;
+
 	if (rscsi_disks[target].device->removable) {
+		SDev->allow_revalidate = 1;
 		check_disk_change(inode->i_rdev);
+		SDev->allow_revalidate = 0;
 
 		/*
 		 * If the drive is empty, just let the open fail.
 		 */
-		if (!rscsi_disks[target].ready)
-			return -ENXIO;
+		if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) {
+			retval = -ENOMEDIUM;
+			goto error_out;
+		}
 
 		/*
 		 * 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 ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) {
+			retval = -EROFS;
+			goto error_out;
+		}
 	}
-	SDev = rscsi_disks[target].device;
 	/*
 	 * 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,
@@ -473,26 +496,31 @@
 	 * the open actually succeeded.
 	 */
 	if (!SDev->online) {
-		return -ENXIO;
+		goto error_out;
 	}
 	/*
 	 * See if we are requesting a non-existent partition.  Do this
 	 * after checking for disk change.
 	 */
-	if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
-		return -ENXIO;
+	if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) {
+		goto error_out;
+	}
 
 	if (SDev->removable)
-		if (!SDev->access_count)
+		if (SDev->access_count==1)
 			if (scsi_block_when_processing_errors(SDev))
 				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
 
-	SDev->access_count++;
+	
+	return 0;
+
+error_out:
+	SDev->access_count--;
 	if (SDev->host->hostt->module)
-		__MOD_INC_USE_COUNT(SDev->host->hostt->module);
+		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
 	if (sd_template.module)
-		__MOD_INC_USE_COUNT(sd_template.module);
-	return 0;
+		__MOD_DEC_USE_COUNT(sd_template.module);
+	return retval;	
 }
 
 static int sd_release(struct inode *inode, struct file *file)
@@ -746,7 +774,8 @@
 
 		while (retries < 3) {
 			cmd[0] = TEST_UNIT_READY;
-			cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+			cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+				 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
 			memset((void *) &cmd[2], 0, 8);
 			SRpnt->sr_cmd_len = 0;
 			SRpnt->sr_sense_buffer[0] = 0;
@@ -787,7 +816,8 @@
 			if (!spintime) {
 				printk("%s: Spinning up disk...", nbuff);
 				cmd[0] = START_STOP;
-				cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+				cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+				 	 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
 				cmd[1] |= 1;	/* Return immediately */
 				memset((void *) &cmd[2], 0, 8);
 				cmd[4] = 1;	/* Start spin cycle */
@@ -820,7 +850,8 @@
 	retries = 3;
 	do {
 		cmd[0] = READ_CAPACITY;
-		cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+		cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+			 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
 		memset((void *) &cmd[2], 0, 8);
 		memset((void *) buffer, 0, 8);
 		SRpnt->sr_cmd_len = 0;
@@ -977,7 +1008,8 @@
 
 		memset((void *) &cmd[0], 0, 8);
 		cmd[0] = MODE_SENSE;
-		cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+		cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+			 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
 		cmd[2] = 0x3f;	/* Get all pages */
 		cmd[4] = 8;     /* But we only want the 8 byte header */
 		SRpnt->sr_cmd_len = 0;
@@ -1183,16 +1215,9 @@
 
 static int sd_detect(Scsi_Device * SDp)
 {
-	char nbuff[6];
 	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
 		return 0;
-
-	sd_devname(sd_template.dev_noticed++, nbuff);
-	printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
-	       SDp->removable ? "removable " : "",
-	       nbuff,
-	       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+	sd_template.dev_noticed++;
 	return 1;
 }
 
@@ -1201,6 +1226,7 @@
         unsigned int devnum;
 	Scsi_Disk *dpnt;
 	int i;
+	char nbuff[6];
 
 	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
 		return 0;
@@ -1224,10 +1250,15 @@
         SD_GENDISK(i).de_arr[devnum] = SDp->de;
         if (SDp->removable)
 		SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE;
+	sd_devname(i, nbuff);
+	printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
+	       SDp->removable ? "removable " : "",
+	       nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 	return 0;
 }
 
 #define DEVICE_BUSY rscsi_disks[target].device->busy
+#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate
 #define USAGE rscsi_disks[target].device->access_count
 #define CAPACITY rscsi_disks[target].capacity
 #define MAYBE_REINIT  sd_init_onedisk(target)
@@ -1248,7 +1279,7 @@
 
 	target = DEVICE_NR(dev);
 
-	if (DEVICE_BUSY || USAGE > maxusage) {
+	if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) {
 		printk("Device busy for revalidation (usage=%d)\n", USAGE);
 		return -EBUSY;
 	}
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.4.6/linux/drivers/scsi/sg.c	Mon Jan 15 13:08:15 2001
+++ linux/drivers/scsi/sg.c	Wed Jul  4 15:39:28 2001
@@ -7,7 +7,7 @@
  * Original driver (sg.c):
  *        Copyright (C) 1992 Lawrence Foard
  * Version 2 and 3 extensions to driver:
- *        Copyright (C) 1998 - 2000 Douglas Gilbert
+ *        Copyright (C) 1998 - 2001 Douglas Gilbert
  *
  *  Modified  19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Devfs support
  *
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char * sg_version_str = "Version: 3.1.17 (20001002)";
+ static char sg_version_str[] = "Version: 3.1.19 (20010623)";
 #endif
- static int sg_version_num = 30117; /* 2 digits for each component */
+ static int sg_version_num = 30119; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -76,8 +76,9 @@
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
-/* #define SG_ALLOW_DIO */
-#ifdef SG_ALLOW_DIO
+#define SG_ALLOW_DIO_DEF 0
+#define SG_ALLOW_DIO_CODE	/* compile out be commenting this define */
+#ifdef SG_ALLOW_DIO_CODE
 #include <linux/iobuf.h>
 #endif
 
@@ -89,6 +90,7 @@
    readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
    the kernel (i.e. it is not a module).] */
 static int def_reserved_size = -1;      /* picks up init parameter */
+static int sg_allow_dio = SG_ALLOW_DIO_DEF;
 
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -112,7 +114,7 @@
 static int sg_detect(Scsi_Device *);
 static void sg_detach(Scsi_Device *);
 
-static Scsi_Request * dummy_cmdp = 0;    /* only used for sizeof */
+static Scsi_Request * dummy_cmdp;	/* only used for sizeof */
 
 static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED;  /* Also used to lock
 			file descriptor list for device */
@@ -157,7 +159,7 @@
     char res_used;              /* 1 -> using reserve buffer, 0 -> not ... */
     char orphan;                /* 1 -> drop on sight, 0 -> normal */
     char sg_io_owned;           /* 1 -> packet belongs to SG_IO */
-    char done;                  /* 0->before bh, 1->before read, 2->read */
+    volatile char done;         /* 0->before bh, 1->before read, 2->read */
 } Sg_request; /* 168 bytes long on i386 */
 
 typedef struct sg_fd /* holds the state of a file descriptor */
@@ -174,12 +176,12 @@
     Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
     char low_dma;       /* as in parent but possibly overridden to 1 */
     char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
-    char closed;        /* 1 -> fd closed but request(s) outstanding */
+    volatile char closed; /* 1 -> fd closed but request(s) outstanding */
     char fd_mem_src;    /* heap whereabouts of this Sg_fd object */
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
     char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
-} Sg_fd; /* 2768 bytes long on i386 */
+} Sg_fd; /* 2760 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
 {
@@ -189,10 +191,10 @@
     Sg_fd * headfp;     /* first open fd belonging to this device */
     devfs_handle_t de;
     kdev_t i_rdev;      /* holds device major+minor number */
-    char exclude;       /* opened for exclusive access */
+    volatile char detached;  /* 0->attached, 1->detached pending removal */
+    volatile char exclude;   /* opened for exclusive access */
     char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
-    char detached;      /* 0->attached, 1->detached pending removal */
-} Sg_device; /* 44 bytes long on i386 */
+} Sg_device; /* 36 bytes long on i386 */
 
 
 static int sg_fasync(int fd, struct file * filp, int mode);
@@ -225,13 +227,12 @@
 static void sg_low_free(char * buff, int size, int mem_src);
 static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
+static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static int sg_dio_in_use(Sg_fd * sfp);
 static void sg_clr_srpnt(Scsi_Request * SRpnt);
-static void sg_shorten_timeout(Scsi_Request * srpnt);
 static int sg_ms_to_jif(unsigned int msecs);
 static unsigned sg_jif_to_ms(int jifs);
 static int sg_allow_access(unsigned char opcode, char dev_type);
@@ -244,10 +245,10 @@
 
 static Sg_device ** sg_dev_arr = NULL;
 
-static const int size_sg_header = sizeof(struct sg_header);
-static const int size_sg_io_hdr = sizeof(sg_io_hdr_t);
-static const int size_sg_iovec = sizeof(sg_iovec_t);
-static const int size_sg_req_info = sizeof(sg_req_info_t);
+#define SZ_SG_HEADER sizeof(struct sg_header)
+#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
+#define SZ_SG_IOVEC sizeof(sg_iovec_t)
+#define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
 
 
 static int sg_open(struct inode * inode, struct file * filp)
@@ -257,43 +258,56 @@
     Sg_device * sdp;
     Sg_fd * sfp;
     int res;
+    int retval = -EBUSY;
 
+    SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
     sdp = sg_get_dev(dev);
-    if ((! sdp) || (! sdp->device) || (! sdp->device->host))
-        return -ENXIO;
-    if (sdp->i_rdev != inode->i_rdev)
-        printk("sg_open: inode maj=%d, min=%d   sdp maj=%d, min=%d\n",
-               MAJOR(inode->i_rdev), MINOR(inode->i_rdev),
-               MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev));
-    /* If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.  */
-    if (! ((flags & O_NONBLOCK) || 
-	   scsi_block_when_processing_errors(sdp->device)))
+    if ((! sdp) || (! sdp->device))
         return -ENXIO;
+    if (sdp->detached)
+    	return -ENODEV;
 
-    SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
+     /* This driver's module count bumped by fops_get in <linux/fs.h> */
+     /* Prevent the device driver from vanishing while we sleep */
+     if (sdp->device->host->hostt->module)
+        __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
+
+    if (! ((flags & O_NONBLOCK) ||
+	   scsi_block_when_processing_errors(sdp->device))) {
+        retval = -ENXIO;
+	/* we are in error recovery for this device */
+	goto error_out;
+    }
 
     if (flags & O_EXCL) {
-        if (O_RDONLY == (flags & O_ACCMODE))
-            return -EACCES;   /* Can't lock it with read only access */
-        if (sdp->headfp && (flags & O_NONBLOCK))
-            return -EBUSY;
-        res = 0;  /* following is a macro that beats race condition */
+        if (O_RDONLY == (flags & O_ACCMODE))  {
+            retval = -EACCES;   /* Can't lock it with read only access */
+	    goto error_out;
+	}
+	if (sdp->headfp && (flags & O_NONBLOCK))
+            goto error_out;
+        res = 0; 
 	__wait_event_interruptible(sdp->o_excl_wait,
 	       ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)),
                                    res);
-        if (res)
-            return res; /* -ERESTARTSYS because signal hit process */
+        if (res) {
+            retval = res; /* -ERESTARTSYS because signal hit process */
+	    goto error_out;
+        }
     }
     else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
         if (flags & O_NONBLOCK)
-            return -EBUSY;
-        res = 0;  /* following is a macro that beats race condition */
+            goto error_out;
+        res = 0; 
         __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
-        if (res)
-            return res; /* -ERESTARTSYS because signal hit process */
+        if (res) {
+            retval = res; /* -ERESTARTSYS because signal hit process */
+	    goto error_out;
+        }
+    }
+    if (sdp->detached) {
+    	retval = -ENODEV;
+	goto error_out;
     }
     if (! sdp->headfp) { /* no existing opens on this device */
         sdp->sgdebug = 0;
@@ -303,12 +317,15 @@
         filp->private_data = sfp;
     else {
         if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */
-        return -ENOMEM;
+        retval = -ENOMEM;
+	goto error_out;
     }
-
-    if (sdp->device->host->hostt->module)
-        __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
     return 0;
+
+error_out:
+    if ((! sdp->detached) && sdp->device->host->hostt->module)
+        __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+    return retval;
 }
 
 /* Following function was formerly called 'sg_close' */
@@ -324,14 +341,12 @@
     }
     SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev)));
     sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
-    sg_remove_sfp(sdp, sfp);
-    if (! sdp->headfp)
-        filp->private_data = NULL;
-
-    if (sdp->device->host->hostt->module)
-        __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
-    sdp->exclude = 0;
-    wake_up_interruptible(&sdp->o_excl_wait);
+    if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
+	if ((! sdp->detached) && sdp->device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+	sdp->exclude = 0;
+	wake_up_interruptible(&sdp->o_excl_wait);
+    }
     unlock_kernel();
     return 0;
 }
@@ -356,11 +371,11 @@
         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
     if ((k = verify_area(VERIFY_WRITE, buf, count)))
         return k;
-    if (sfp->force_packid && (count >= size_sg_header)) {
-	__copy_from_user(&old_hdr, buf, size_sg_header);
+    if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
+	__copy_from_user(&old_hdr, buf, SZ_SG_HEADER);
 	if (old_hdr.reply_len < 0) {
-	    if (count >= size_sg_io_hdr) {
-		__copy_from_user(&new_hdr, buf, size_sg_io_hdr);
+	    if (count >= SZ_SG_IO_HDR) {
+		__copy_from_user(&new_hdr, buf, SZ_SG_IO_HDR);
 		req_pack_id = new_hdr.pack_id;
 	    }
 	}
@@ -369,25 +384,26 @@
     }
     srp = sg_get_rq_mark(sfp, req_pack_id);
     if (! srp) { /* now wait on packet to arrive */
+	if (sdp->detached)
+	    return -ENODEV;
         if (filp->f_flags & O_NONBLOCK)
             return -EAGAIN;
 	while (1) {
-	    int dio = sg_dio_in_use(sfp);
 	    res = 0;  /* following is a macro that beats race condition */
-	    __wait_event_interruptible(sfp->read_wait,
-                                   (srp = sg_get_rq_mark(sfp, req_pack_id)),
-                                   res);
+	    __wait_event_interruptible(sfp->read_wait, (sdp->detached || 
+		    (srp = sg_get_rq_mark(sfp, req_pack_id))), res);
+	    if (sdp->detached)
+		return -ENODEV;
 	    if (0 == res)
 		break;
-	    else if (! dio)     /* only let signal out if no dio */
-		return res; /* -ERESTARTSYS because signal hit process */
+	    return res; /* -ERESTARTSYS because signal hit process */
 	}
     }
     if (srp->header.interface_id != '\0')
 	return sg_new_read(sfp, buf, count, srp);
 
     hp = &srp->header;
-    memset(&old_hdr, 0, size_sg_header);
+    memset(&old_hdr, 0, SZ_SG_HEADER);
     old_hdr.reply_len = (int)hp->timeout;
     old_hdr.pack_len = old_hdr.reply_len;   /* very old, strange behaviour */
     old_hdr.pack_id = hp->pack_id;
@@ -430,13 +446,13 @@
     }
 
     /* Now copy the result back to the user buffer.  */
-    if (count >= size_sg_header) {
-	__copy_to_user(buf, &old_hdr, size_sg_header);
-        buf += size_sg_header;
+    if (count >= SZ_SG_HEADER) {
+	__copy_to_user(buf, &old_hdr, SZ_SG_HEADER);
+        buf += SZ_SG_HEADER;
 	if (count > old_hdr.reply_len)
 	    count = old_hdr.reply_len;
-	if (count > size_sg_header)
-	    sg_read_oxfer(srp, buf, count - size_sg_header);
+	if (count > SZ_SG_HEADER)
+	    sg_read_oxfer(srp, buf, count - SZ_SG_HEADER);
     }
     else
 	count = (old_hdr.result == 0) ? 0 : -EIO;
@@ -447,11 +463,14 @@
 static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
 			   Sg_request * srp)
 {
-    sg_io_hdr_t         * hp = &srp->header;
-    int                   k, len;
+    sg_io_hdr_t * hp = &srp->header;
+    int err = 0;
+    int len;
 
-    if (count < size_sg_io_hdr)
-	return -EINVAL;
+    if (count < SZ_SG_IO_HDR) {
+	err = -EINVAL;
+    	goto err_out;
+    }
     hp->sb_len_wr = 0;
     if ((hp->mx_sb_len > 0) && hp->sbp) {
 	if ((CHECK_CONDITION & hp->masked_status) ||
@@ -460,20 +479,19 @@
 	    sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
 	    len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */
 	    len = (len > sb_len) ? sb_len : len;
-	    if ((k = verify_area(VERIFY_WRITE, hp->sbp, len)))
-		return k;
+	    if ((err = verify_area(VERIFY_WRITE, hp->sbp, len)))
+		goto err_out;
 	    __copy_to_user(hp->sbp, srp->sense_b, len);
 	    hp->sb_len_wr = len;
 	}
     }
     if (hp->masked_status || hp->host_status || hp->driver_status)
 	hp->info |= SG_INFO_CHECK;
-    copy_to_user(buf, hp, size_sg_io_hdr);
-
-    k = sg_read_xfer(srp);
-    if (k) return k; /* probably -EFAULT, bad addr in dxferp or iovec list */
+    copy_to_user(buf, hp, SZ_SG_IO_HDR);
+    err = sg_read_xfer(srp);
+err_out:
     sg_finish_rem_req(srp);
-    return count;
+    return (0 == err) ? count : err;
 }
 
 
@@ -494,7 +512,8 @@
         return -ENXIO;
     SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
                                MINOR(sdp->i_rdev), (int)count));
-
+    if (sdp->detached)
+    	return -ENODEV;
     if (! ((filp->f_flags & O_NONBLOCK) ||
            scsi_block_when_processing_errors(sdp->device)))
         return -ENXIO;
@@ -503,20 +522,20 @@
 
     if ((k = verify_area(VERIFY_READ, buf, count)))
         return k;  /* protects following copy_from_user()s + get_user()s */
-    if (count < size_sg_header)
+    if (count < SZ_SG_HEADER)
 	return -EIO;
-    __copy_from_user(&old_hdr, buf, size_sg_header);
+    __copy_from_user(&old_hdr, buf, SZ_SG_HEADER);
     blocking = !(filp->f_flags & O_NONBLOCK);
     if (old_hdr.reply_len < 0)
 	return sg_new_write(sfp, buf, count, blocking, 0, NULL);
-    if (count < (size_sg_header + 6))
+    if (count < (SZ_SG_HEADER + 6))
 	return -EIO;   /* The minimum scsi command length is 6 bytes. */
 
     if (! (srp = sg_add_request(sfp))) {
 	SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
 	return -EDOM;
     }
-    buf += size_sg_header;
+    buf += SZ_SG_HEADER;
     __get_user(opcode, buf);
     if (sfp->next_cmd_len > 0) {
         if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
@@ -539,8 +558,8 @@
     input_size = count - cmd_size;
     mxsize = (input_size > old_hdr.reply_len) ? input_size :
 						old_hdr.reply_len;
-    mxsize -= size_sg_header;
-    input_size -= size_sg_header;
+    mxsize -= SZ_SG_HEADER;
+    input_size -= SZ_SG_HEADER;
     if (input_size < 0) {
         sg_remove_request(sfp, srp);
         return -EIO; /* User did not pass enough bytes for this command. */
@@ -550,16 +569,12 @@
     hp->cmd_len = (unsigned char)cmd_size;
     hp->iovec_count = 0;
     hp->mx_sb_len = 0;
-#if 0
-    hp->dxfer_direction = SG_DXFER_UNKNOWN;
-#else
     if (input_size > 0)
-	hp->dxfer_direction = ((old_hdr.reply_len - size_sg_header) > 0) ?
+	hp->dxfer_direction = ((old_hdr.reply_len - SZ_SG_HEADER) > 0) ?
 			      SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
     else
 	hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
 					     SG_DXFER_NONE;
-#endif
     hp->dxfer_len = mxsize;
     hp->dxferp = (unsigned char *)buf + cmd_size;
     hp->sbp = NULL;
@@ -581,7 +596,7 @@
     unsigned char         cmnd[sizeof(dummy_cmdp->sr_cmnd)];
     int                   timeout;
 
-    if (count < size_sg_io_hdr)
+    if (count < SZ_SG_IO_HDR)
 	return -EINVAL;
     if ((k = verify_area(VERIFY_READ, buf, count)))
 	return k;  /* protects following copy_from_user()s + get_user()s */
@@ -592,7 +607,7 @@
 	return -EDOM;
     }
     hp = &srp->header;
-    __copy_from_user(hp, buf, size_sg_io_hdr);
+    __copy_from_user(hp, buf, SZ_SG_IO_HDR);
     if (hp->interface_id != 'S') {
 	sg_remove_request(sfp, srp);
 	return -ENOSYS;
@@ -648,7 +663,10 @@
 	sg_finish_rem_req(srp);
 	return k;
     }
-/*  SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
+    if (sdp->detached) {
+    	sg_finish_rem_req(srp);
+    	return -ENODEV;
+    }
     SRpnt = scsi_allocate_request(sdp->device);
     if(SRpnt == NULL) {
     	SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n"));
@@ -656,17 +674,15 @@
     	return -ENOMEM;
     }
 
-/*  SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */
     srp->my_cmdp = SRpnt;
     SRpnt->sr_request.rq_dev = sdp->i_rdev;
     SRpnt->sr_request.rq_status = RQ_ACTIVE;
     SRpnt->sr_sense_buffer[0] = 0;
     SRpnt->sr_cmd_len = hp->cmd_len;
-/* Set the LUN field in the command structure, overriding user input  */
-    if (! (hp->flags & SG_FLAG_LUN_INHIBIT))
-	cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
-
-/*  SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
+    if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
+	if (sdp->device->scsi_level <= SCSI_2)
+	    cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
+    }
     SRpnt->sr_use_sg = srp->data.k_use_sg;
     SRpnt->sr_sglist_len = srp->data.sglist_len;
     SRpnt->sr_bufflen = srp->data.bufflen;
@@ -719,30 +735,31 @@
 	{
 	    int blocking = 1;   /* ignore O_NONBLOCK flag */
 
+	    if (sdp->detached)
+		return -ENODEV;
 	    if(! scsi_block_when_processing_errors(sdp->device) )
 		return -ENXIO;
-	    result = verify_area(VERIFY_WRITE, (void *)arg, size_sg_io_hdr);
+	    result = verify_area(VERIFY_WRITE, (void *)arg, SZ_SG_IO_HDR);
 	    if (result) return result;
-	    result = sg_new_write(sfp, (const char *)arg, size_sg_io_hdr,
+	    result = sg_new_write(sfp, (const char *)arg, SZ_SG_IO_HDR,
 				  blocking, read_only, &srp);
 	    if (result < 0) return result;
 	    srp->sg_io_owned = 1;
 	    while (1) {
-		int dio = sg_dio_in_use(sfp);
 		result = 0;  /* following macro to beat race condition */
 		__wait_event_interruptible(sfp->read_wait,
-				   (sfp->closed || srp->done), result);
+		       (sdp->detached || sfp->closed || srp->done), result);
+		if (sdp->detached)
+		    return -ENODEV;
 		if (sfp->closed)
 		    return 0;       /* request packet dropped already */
 		if (0 == result)
 		    break;
-		else if (! dio) {       /* only let signal out if no dio */
-		    srp->orphan = 1;
-		    return result; /* -ERESTARTSYS because signal hit process */
-		}
+		srp->orphan = 1;
+		return result; /* -ERESTARTSYS because signal hit process */
 	    }
 	    srp->done = 2;
-	    result = sg_new_read(sfp, (char *)arg, size_sg_io_hdr, srp);
+	    result = sg_new_read(sfp, (char *)arg, SZ_SG_IO_HDR, srp);
 	    return (result < 0) ? result : 0;
 	}
     case SG_SET_TIMEOUT:
@@ -765,8 +782,11 @@
                 sg_build_reserve(sfp, val);
             }
         }
-        else
+        else {
+	    if (sdp->detached)
+		return -ENODEV;
             sfp->low_dma = sdp->device->host->unchecked_isa_dma;
+	}
         return 0;
     case SG_GET_LOW_DMA:
         return put_user((int)sfp->low_dma, (int *)arg);
@@ -775,6 +795,9 @@
         if (result) return result;
         else {
 	    sg_scsi_id_t * sg_idp = (sg_scsi_id_t *)arg;
+
+	    if (sdp->detached)
+		return -ENODEV;
             __put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
             __put_user((int)sdp->device->channel, &sg_idp->channel);
             __put_user((int)sdp->device->id, &sg_idp->scsi_id);
@@ -853,7 +876,7 @@
         return put_user(sg_version_num, (int *)arg);
     case SG_GET_REQUEST_TABLE:
 	result = verify_area(VERIFY_WRITE, (void *) arg,
-			     size_sg_req_info * SG_MAX_QUEUE);
+			     SZ_SG_REQ_INFO * SG_MAX_QUEUE);
 	if (result) return result;
 	else {
 	    sg_req_info_t rinfo[SG_MAX_QUEUE];
@@ -861,7 +884,7 @@
 	    read_lock_irqsave(&sfp->rq_list_lock, iflags);
 	    for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
 		 ++val, srp = srp ? srp->nextrp : srp) {
-		memset(&rinfo[val], 0, size_sg_req_info);
+		memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
 		if (srp) {
 		    rinfo[val].req_state = srp->done + 1;
 		    rinfo[val].problem = srp->header.masked_status &
@@ -876,12 +899,16 @@
 		}
 	    }
 	    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-	    __copy_to_user((void *)arg, rinfo, size_sg_req_info * SG_MAX_QUEUE);
+	    __copy_to_user((void *)arg, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE);
 	    return 0;
 	}
     case SG_EMULATED_HOST:
+	if (sdp->detached)
+	    return -ENODEV;
         return put_user(sdp->device->host->hostt->emulated, (int *)arg);
     case SG_SCSI_RESET:
+	if (sdp->detached)
+	    return -ENODEV;
         if (filp->f_flags & O_NONBLOCK) {
 	    if (sdp->device->host->in_recovery)
 		return -EBUSY;
@@ -907,13 +934,16 @@
 	default:
 	    return -EINVAL;
 	}
-	if(! capable(CAP_SYS_ADMIN))  return -EACCES;
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+	    return -EACCES;
 	return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
 #else
 	SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
 	result = -EINVAL;
 #endif
     case SCSI_IOCTL_SEND_COMMAND:
+	if (sdp->detached)
+	    return -ENODEV;
 	if (read_only) {
 	    unsigned char opcode = WRITE_6;
 	    Scsi_Ioctl_Command * siocp = (void *)arg;
@@ -932,6 +962,8 @@
     case SCSI_IOCTL_GET_BUS_NUMBER:
     case SCSI_IOCTL_PROBE_HOST:
     case SG_GET_TRANSFORM:
+	if (sdp->detached)
+	    return -ENODEV;
         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
     default:
 	if (read_only)
@@ -949,7 +981,8 @@
     int count = 0;
     unsigned long iflags;
 
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
+    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))
+    	|| sfp->closed)
         return POLLERR;
     poll_wait(filp, &sfp->read_wait, wait);
     read_lock_irqsave(&sfp->rq_list_lock, iflags);
@@ -960,7 +993,10 @@
         ++count;
     }
     read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    if (! sfp->cmd_q) {
+
+    if (sdp->detached)
+	res |= POLLHUP;
+    else if (! sfp->cmd_q) {
         if (0 == count)
             res |= POLLOUT | POLLWRNORM;
     }
@@ -1001,9 +1037,9 @@
 	if (dev < sg_template.dev_max)
 	    sdp = sg_dev_arr[dev];
     }
-    if (NULL == sdp) {
+    if ((NULL == sdp) || sdp->detached) {
 	read_unlock(&sg_dev_arr_lock);
-	SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev));
+	SCSI_LOG_TIMEOUT(1, printk("sg...bh: dev=%d gone\n", dev));
         scsi_release_request(SRpnt);
         SRpnt = NULL;
         return;
@@ -1020,8 +1056,8 @@
             break;
         sfp = sfp->nextfp;
     }
-    read_unlock(&sg_dev_arr_lock);
     if (! srp) {
+	read_unlock(&sg_dev_arr_lock);
 	SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev));
         scsi_release_request(SRpnt);
         SRpnt = NULL;
@@ -1035,6 +1071,7 @@
     sg_clr_srpnt(SRpnt);
     srp->my_cmdp = NULL;
     srp->done = 1;
+    read_unlock(&sg_dev_arr_lock);
 
     SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n",
 		     dev, srp->header.pack_id, (int)SRpnt->sr_result));
@@ -1071,7 +1108,6 @@
     if (sfp->closed) { /* whoops this fd already released, cleanup */
         SCSI_LOG_TIMEOUT(1,
 	       printk("sg...bh: already closed, freeing ...\n"));
-	/* should check if module is unloaded <<<<<<< */
 	sg_finish_rem_req(srp);
 	srp = NULL;
 	if (NULL == sfp->headrp) {
@@ -1080,6 +1116,10 @@
             sg_remove_sfp(sdp, sfp);
 	    sfp = NULL;
         }
+	if (sg_template.module)
+		__MOD_DEC_USE_COUNT(sg_template.module);
+	if (sdp->device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
     }
     else if (srp && srp->orphan) {
 	if (sfp->keep_orphan)
@@ -1110,19 +1150,6 @@
 
 static int sg_detect(Scsi_Device * scsidp)
 {
-    switch (scsidp->type) {
-        case TYPE_DISK:
-        case TYPE_MOD:
-        case TYPE_ROM:
-        case TYPE_WORM:
-        case TYPE_TAPE: break;
-        default:
-        printk("Detected scsi generic sg%d at scsi%d,"
-                " channel %d, id %d, lun %d, type %d\n",
-               sg_template.dev_noticed,
-	       scsidp->host->host_no, scsidp->channel,
-               scsidp->id, scsidp->lun, scsidp->type);
-    }
     sg_template.dev_noticed++;
     return 1;
 }
@@ -1241,51 +1268,73 @@
     sg_template.nr_dev++;
     sg_dev_arr[k] = sdp;
     write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+    switch (scsidp->type) {
+	case TYPE_DISK:
+	case TYPE_MOD:
+	case TYPE_ROM:
+	case TYPE_WORM:
+	case TYPE_TAPE: break;
+	default:
+	    printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
+		   " lun %d,  type %d\n", k, scsidp->host->host_no, 
+		   scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
+    }
     return 0;
 }
 
 /* Called at 'finish' of init process, after all attaches */
 static void sg_finish(void)
-{
-    SCSI_LOG_TIMEOUT(3, printk("sg_finish: dma_free_sectors=%u\n",
-                     scsi_dma_free_sectors));
-}
+{ }
 
 static void sg_detach(Scsi_Device * scsidp)
 {
     Sg_device * sdp;
     unsigned long iflags;
     Sg_fd * sfp;
+    Sg_fd * tsfp;
     Sg_request * srp;
-    int k;
+    Sg_request * tsrp;
+    int k, delay;
 
     if (NULL == sg_dev_arr)
     	return;
+    delay = 0;
     write_lock_irqsave(&sg_dev_arr_lock, iflags);
     for (k = 0; k < sg_template.dev_max; k++) {
     	sdp = sg_dev_arr[k];
         if ((NULL == sdp) || (sdp->device != scsidp))
             continue;   /* dirty but lowers nesting */
         if (sdp->headfp) {
-	    for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) {
-		/* no lock on request list here */
-		for (srp = sfp->headrp; srp; srp = srp->nextrp) {
-		    if (! srp->done) {
-			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-                        sg_shorten_timeout(srp->my_cmdp);
-			write_lock_irqsave(&sg_dev_arr_lock, iflags);
-                }
-            }
+	    sdp->detached = 1;
+	    for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+	    	tsfp = sfp->nextfp;
+		for (srp = sfp->headrp; srp; srp = tsrp) {
+		    tsrp = srp->nextrp;
+		    if (sfp->closed || (0 == srp->done))
+			sg_finish_rem_req(srp);
+		}
+		if (sfp->closed) {
+		    if (sg_template.module)
+			__MOD_DEC_USE_COUNT(sg_template.module);
+		    if (sdp->device->host->hostt->module)
+			__MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+		    __sg_remove_sfp(sdp, sfp);
+		}
+		else {
+		    delay = 1;
+		    wake_up_interruptible(&sfp->read_wait);
+		    kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
+		}
             }
-	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k));
-            scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */
+	    SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
 	    devfs_unregister (sdp->de);
 	    sdp->de = NULL;
-	    sdp->detached = 1;
-	    write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	    if (NULL == sdp->headfp) {
+		kfree((char *)sdp);
+		sg_dev_arr[k] = NULL;
+	    }
         }
-        else {
+        else { /* nothing active, simple case */
             SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
 	    devfs_unregister (sdp->de);
 	    kfree((char *)sdp);
@@ -1293,13 +1342,12 @@
         }
         scsidp->attached--;
         sg_template.nr_dev--;
-/* avoid associated device /dev/sg? being incremented
- * each time module is inserted/removed , <dan@lectra.fr> */
-        sg_template.dev_noticed--;
+        sg_template.dev_noticed--;	/* from <dan@lectra.fr> */
         break;
     }
     write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-    return;
+    if (delay)
+	scsi_sleep(2);	/* dirty detach so delay device destruction */
 }
 
 MODULE_AUTHOR("Douglas Gilbert");
@@ -1322,8 +1370,6 @@
     scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
     devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
     if(sg_dev_arr != NULL) {
-/* Really worrying situation of writes still pending and get here */
-/* Strategy: shorten timeout on release + wait on detach ... */
 	kfree((char *)sg_dev_arr);
         sg_dev_arr = NULL;
     }
@@ -1331,29 +1377,6 @@
 }
 
 
-#if 0
-extern void scsi_times_out (Scsi_Cmnd * SCpnt);
-extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
-#endif
-
-/* Can't see clean way to abort a command so shorten timeout to 1 jiffy */
-static void sg_shorten_timeout(Scsi_Request * srpnt)
-{
-#if 0 /* scsi_syms.c is very miserly about exported functions */
-    scsi_delete_timer(scpnt);
-    if (! scpnt)
-        return;
-    scpnt->timeout_per_command = 1; /* try 1 jiffy (perhaps 0 jiffies) */
-    if (scpnt->host->hostt->use_new_eh_code)
-        scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_times_out);
-    else
-        scsi_add_timer(scpnt, scpnt->timeout_per_command,
-                       scsi_old_times_out);
-#else
-    scsi_sleep(HZ); /* just sleep 1 second and hope ... */
-#endif
-}
-
 static int sg_start_req(Sg_request * srp)
 {
     int res;
@@ -1367,9 +1390,8 @@
     SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
     if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
     	return 0;
-    if ((hp->flags & SG_FLAG_DIRECT_IO) && 
-	(dxfer_dir != SG_DXFER_UNKNOWN) &&
-	(0 == hp->iovec_count) &&
+    if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) && 
+	(dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
 	(! sfp->parentdp->device->host->unchecked_isa_dma)) {
 	res = sg_build_dir(srp, sfp, dxfer_len);
 	if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
@@ -1427,7 +1449,7 @@
 
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
 {
-#ifdef SG_ALLOW_DIO
+#ifdef SG_ALLOW_DIO_CODE
     if (schp && schp->kiobp) {
 	if (schp->mapped) {
 	    unmap_kiobuf(schp->kiobp);
@@ -1443,7 +1465,7 @@
 
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
 {
-#ifdef SG_ALLOW_DIO
+#ifdef SG_ALLOW_DIO_CODE
     int res, k, split, offset, num, mx_sc_elems, rem_sz;
     struct kiobuf * kp;
     char * mem_src_arr;
@@ -1519,7 +1541,7 @@
     return 0;
 #else
     return 1;
-#endif /* SG_ALLOW_DIO */
+#endif /* SG_ALLOW_DIO_CODE */
 }
 
 static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
@@ -1629,7 +1651,7 @@
     if (iovec_count) {
 	onum = iovec_count;
 	if ((k = verify_area(VERIFY_READ, hp->dxferp,
-			     size_sg_iovec * onum)))
+			     SZ_SG_IOVEC * onum)))
 	    return k;
     }
     else
@@ -1707,8 +1729,8 @@
     }
     else {
 	__copy_from_user(&u_iovec,
-			 (unsigned char *)hp->dxferp + (ind * size_sg_iovec),
-			 size_sg_iovec);
+			 (unsigned char *)hp->dxferp + (ind * SZ_SG_IOVEC),
+			 SZ_SG_IOVEC);
 	p = (unsigned char *)u_iovec.iov_base;
 	count = (int)u_iovec.iov_len;
     }
@@ -1778,7 +1800,7 @@
     if (iovec_count) {
 	onum = iovec_count;
 	if ((k = verify_area(VERIFY_READ, hp->dxferp,
-			     size_sg_iovec * onum)))
+			     SZ_SG_IOVEC * onum)))
 	    return k;
     }
     else
@@ -2124,6 +2146,34 @@
     return sfp;
 }
 
+static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+{
+    Sg_fd * fp;
+    Sg_fd * prev_fp;
+
+    prev_fp =  sdp->headfp;
+    if (sfp == prev_fp)
+	sdp->headfp = prev_fp->nextfp;
+    else {
+	while ((fp = prev_fp->nextfp)) {
+	    if (sfp == fp) {
+		prev_fp->nextfp = fp->nextfp;
+		break;
+	    }
+	    prev_fp = fp;
+	}
+    }
+    if (sfp->reserve.bufflen > 0) {
+    SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
+	     (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+	sg_remove_scat(&sfp->reserve);
+    }
+    sfp->parentdp = NULL;
+    SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    sfp=0x%p\n", sfp));
+    sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src);
+}
+
+/* Returns 0 in normal case, 1 when detached and sdp object removed */
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
 {
     Sg_request * srp;
@@ -2131,44 +2181,18 @@
     int dirty = 0;
     int res = 0;
 
-    srp = sfp->headrp;
-    if (srp) {
-	while (srp) {
-	    tsrp = srp->nextrp;
-	    if (srp->done)
-		sg_finish_rem_req(srp);
-	    else
-		++dirty;
-	    srp = tsrp;
-	}
+    for (srp = sfp->headrp; srp; srp = tsrp) {
+	tsrp = srp->nextrp;
+	if (srp->done)
+	    sg_finish_rem_req(srp);
+	else
+	    ++dirty;
     }
     if (0 == dirty) {
-	Sg_fd * fp;
-	Sg_fd * prev_fp;
 	unsigned long iflags;
 
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	prev_fp =  sdp->headfp;
-	if (sfp == prev_fp)
-	    sdp->headfp = prev_fp->nextfp;
-	else {
-	    while ((fp = prev_fp->nextfp)) {
-		if (sfp == fp) {
-		    prev_fp->nextfp = fp->nextfp;
-		    break;
-		}
-		prev_fp = fp;
-	    }
-	}
-	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	if (sfp->reserve.bufflen > 0) {
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
-		 (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
-	    sg_remove_scat(&sfp->reserve);
-        }
-        sfp->parentdp = NULL;
-	SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%p\n", sfp));
-	sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src);
+	__sg_remove_sfp(sdp, sfp);
 	if (sdp->detached && (NULL == sdp->headfp)) {
 	    int k, maxd;
 
@@ -2180,11 +2204,17 @@
 	    if (k < maxd)
 		sg_dev_arr[k] = NULL;
 	    kfree((char *)sdp);
+	    res = 1;
 	}
-        res = 1;
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
     }
     else {
         sfp->closed = 1; /* flag dirty state on this fd */
+	/* MOD_INC's to inhibit unloading sg and associated adapter driver */
+	if (sg_template.module)
+	    __MOD_INC_USE_COUNT(sg_template.module);
+	 if (sdp->device->host->hostt->module)
+	    __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
         SCSI_LOG_TIMEOUT(1, printk(
           "sg_remove_sfp: worrisome, %d writes pending\n", dirty));
     }
@@ -2203,31 +2233,15 @@
     return srp ? 1 : 0;
 }
 
-static int sg_dio_in_use(Sg_fd * sfp)
-{
-    const Sg_request * srp;
-    unsigned long iflags;
-
-    read_lock_irqsave(&sfp->rq_list_lock, iflags);
-    for (srp = sfp->headrp; srp; srp = srp->nextrp)
-	if ((! srp->done) && srp->data.kiobp) break;
-    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-    return srp ? 1 : 0;
-}
-
 /* If retSzp==NULL want exact size or fail */
-/* sg_low_malloc() should always be called from a process context allowing
-   GFP_KERNEL to be used instead of GFP_ATOMIC */
 static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
 {
     char * resp = NULL;
-    int page_mask = lowDma ? (GFP_KERNEL | GFP_DMA) : GFP_KERNEL;
+    int page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC;
 
     if (rqSz <= 0)
         return resp;
     if (SG_HEAP_KMAL == mem_src) {
-        page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC;
-        /* Seen kmalloc(..,GFP_KERNEL) hang for 40 secs! */
         resp = kmalloc(rqSz, page_mask);
         if (resp && retSzp) *retSzp = rqSz;
         return resp;
@@ -2355,7 +2369,7 @@
     case SG_USER_MEM:
 	break; /* nothing to do */
     default:
-	printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n",
+	printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
                mem_src, buff, size);
 	break;
     }
@@ -2451,11 +2465,17 @@
 
 static struct proc_dir_entry * sg_proc_sgp = NULL;
 
-static const char * sg_proc_sg_dirname = "sg";
-static const char * sg_proc_leaf_names[] = {"def_reserved_size", "debug",
-			    "devices", "device_hdr", "device_strs",
-			    "hosts", "host_hdr", "host_strs", "version"};
+static char sg_proc_sg_dirname[] = "sg";
+static const char * sg_proc_leaf_names[] = {"allow_dio", "def_reserved_size",
+		"debug", "devices", "device_hdr", "device_strs",
+		"hosts", "host_hdr", "host_strs", "version"};
 
+static int sg_proc_adio_read(char * buffer, char ** start, off_t offset,
+			     int size, int * eof, void * data);
+static int sg_proc_adio_info(char * buffer, int * len, off_t * begin,
+			     off_t offset, int size);
+static int sg_proc_adio_write(struct file * filp, const char * buffer,
+			      unsigned long count, void * data);
 static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
 			       int size, int * eof, void * data);
 static int sg_proc_dressz_info(char * buffer, int * len, off_t * begin,
@@ -2495,12 +2515,12 @@
 static int sg_proc_version_info(char * buffer, int * len, off_t * begin,
 				off_t offset, int size);
 static read_proc_t * sg_proc_leaf_reads[] = {
-	     sg_proc_dressz_read, sg_proc_debug_read,
+	     sg_proc_adio_read, sg_proc_dressz_read, sg_proc_debug_read,
 	     sg_proc_dev_read, sg_proc_devhdr_read, sg_proc_devstrs_read,
 	     sg_proc_host_read, sg_proc_hosthdr_read, sg_proc_hoststrs_read,
 	     sg_proc_version_read};
 static write_proc_t * sg_proc_leaf_writes[] = {
-	     sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0};
+	     sg_proc_adio_write, sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0};
 
 #define PRINT_PROC(fmt,args...)                                 \
     do {                                                        \
@@ -2562,6 +2582,32 @@
     remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
 }
 
+static int sg_proc_adio_read(char * buffer, char ** start, off_t offset,
+			       int size, int * eof, void * data)
+{ SG_PROC_READ_FN(sg_proc_adio_info); }
+
+static int sg_proc_adio_info(char * buffer, int * len, off_t * begin,
+			     off_t offset, int size)
+{
+    PRINT_PROC("%d\n", sg_allow_dio);
+    return 1;
+}
+
+static int sg_proc_adio_write(struct file * filp, const char * buffer,
+			      unsigned long count, void * data)
+{
+    int num;
+    char buff[11];
+
+    if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+	return -EACCES;
+    num = (count < 10) ? count : 10;
+    copy_from_user(buff, buffer, num);
+    buff[num] = '\0';
+    sg_allow_dio = simple_strtoul(buff, 0, 10) ? 1 : 0;
+    return count;
+}
+
 static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
 			       int size, int * eof, void * data)
 { SG_PROC_READ_FN(sg_proc_dressz_info); }
@@ -2580,7 +2626,7 @@
     unsigned long k = ULONG_MAX;
     char buff[11];
 
-    if (! capable(CAP_SYS_ADMIN))
+    if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 	return -EACCES;
     num = (count < 10) ? count : 10;
     copy_from_user(buff, buffer, num);
@@ -2620,8 +2666,9 @@
 	    Sg_request * srp;
 	    struct scsi_device * scsidp;
 	    int dev, k, m, blen, usg;
-
-	    if (! (scsidp = sdp->device)) {
+ 
+	    scsidp = sdp->device;
+	    if (NULL == scsidp) {
 		PRINT_PROC("device %d detached ??\n", j);
 		continue;
 	    }
@@ -2629,10 +2676,14 @@
 
 	    if (sg_get_nth_sfp(sdp, 0)) {
 		PRINT_PROC(" >>> device=sg%d ", dev);
-		PRINT_PROC("scsi%d chan=%d id=%d lun=%d   em=%d sg_tablesize=%d"
-		       " excl=%d\n", scsidp->host->host_no, scsidp->channel,
-		       scsidp->id, scsidp->lun, scsidp->host->hostt->emulated,
-		       sdp->sg_tablesize, sdp->exclude);
+		if (sdp->detached)
+		    PRINT_PROC("detached pending close ");
+		else
+		    PRINT_PROC("scsi%d chan=%d id=%d lun=%d   em=%d",
+		       scsidp->host->host_no, scsidp->channel,
+		       scsidp->id, scsidp->lun, scsidp->host->hostt->emulated);
+		PRINT_PROC(" sg_tablesize=%d excl=%d\n", sdp->sg_tablesize, 
+			   sdp->exclude);
 	    }
 	    for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
 		PRINT_PROC("   FD(%d): timeout=%dms bufflen=%d "
@@ -2683,13 +2734,14 @@
     max_dev = sg_last_dev();
     for (j = 0; j < max_dev; ++j) {
 	sdp = sg_get_dev(j);
-	if (sdp && (scsidp = sdp->device))
-	    PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
+	if (sdp && (scsidp = sdp->device) && (! sdp->detached))
+	    PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
 	       scsidp->host->host_no, scsidp->channel, scsidp->id,
 	       scsidp->lun, (int)scsidp->type, (int)scsidp->access_count,
-	       (int)scsidp->queue_depth, (int)scsidp->device_busy);
+	       (int)scsidp->queue_depth, (int)scsidp->device_busy,
+	       (int)scsidp->online);
 	else
-	    PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
+	    PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
     }
     return 1;
 }
@@ -2701,7 +2753,7 @@
 static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin,
 			       off_t offset, int size)
 {
-    PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\n");
+    PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\tonline\n");
     return 1;
 }
 
@@ -2719,7 +2771,7 @@
     max_dev = sg_last_dev();
     for (j = 0; j < max_dev; ++j) {
 	sdp = sg_get_dev(j);
-	if (sdp && (scsidp = sdp->device))
+	if (sdp && (scsidp = sdp->device) && (! sdp->detached))
 	    PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
 		       scsidp->vendor, scsidp->model, scsidp->rev);
 	else
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.4.6/linux/drivers/scsi/sr.c	Sat Apr 28 11:28:08 2001
+++ linux/drivers/scsi/sr.c	Thu Jul  5 11:28:17 2001
@@ -88,6 +88,7 @@
 static int *sr_sizes;
 
 static int *sr_blocksizes;
+static int *sr_hardsizes;
 
 static int sr_open(struct cdrom_device_info *, int);
 void get_sectorsize(int);
@@ -262,7 +263,7 @@
 static int sr_scatter_pad(Scsi_Cmnd *SCpnt, int s_size)
 {
 	struct scatterlist *sg, *old_sg = NULL;
-	int i, fsize, bsize, sg_ent;
+	int i, fsize, bsize, sg_ent, sg_count;
 	char *front, *back;
 
 	back = front = NULL;
@@ -290,17 +291,24 @@
 	/*
 	 * extend or allocate new scatter-gather table
 	 */
-	if (SCpnt->use_sg)
+	sg_count = SCpnt->use_sg;
+	if (sg_count)
 		old_sg = (struct scatterlist *) SCpnt->request_buffer;
 	else {
-		SCpnt->use_sg = 1;
+		sg_count = 1;
 		sg_ent++;
 	}
 
-	SCpnt->sglist_len = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
-	if ((sg = scsi_malloc(SCpnt->sglist_len)) == NULL)
+	i = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
+	if ((sg = scsi_malloc(i)) == NULL)
 		goto no_mem;
 
+	/*
+	 * no more failing memory allocs possible, we can safely assign
+	 * SCpnt values now
+	 */
+	SCpnt->sglist_len = i;
+	SCpnt->use_sg = sg_count;
 	memset(sg, 0, SCpnt->sglist_len);
 
 	i = 0;
@@ -343,12 +351,12 @@
 
 static int sr_init_command(Scsi_Cmnd * SCpnt)
 {
-	int dev, devm, block, this_count, s_size;
+	int dev, devm, block=0, this_count, s_size;
 
 	devm = MINOR(SCpnt->request.rq_dev);
 	dev = DEVICE_NR(SCpnt->request.rq_dev);
 
-	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d\n", devm));
+	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
 
 	if (dev >= sr_template.nr_dev ||
 	    !scsi_CDs[dev].device ||
@@ -415,7 +423,8 @@
 		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
 				 this_count, SCpnt->request.nr_sectors));
 
-	SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+			 ((SCpnt->lun << 5) & 0xe0) : 0;
 
 	if (this_count > 0xffff)
 		this_count = 0xffff;
@@ -501,11 +510,7 @@
 
 	if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
 		return 0;
-
-	printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
-	       sr_template.dev_noticed++,
-	       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+	sr_template.dev_noticed++;
 	return 1;
 }
 
@@ -534,6 +539,9 @@
 	sr_template.nr_dev++;
 	if (sr_template.nr_dev > sr_template.dev_max)
 		panic("scsi_devices corrupt (sr)");
+
+	printk("Attached scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
+	       i, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 	return 0;
 }
 
@@ -564,7 +572,8 @@
 	retries = 3;
 	do {
 		cmd[0] = READ_CAPACITY;
-		cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+		cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
+			 ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
 		memset((void *) &cmd[2], 0, 8);
 		SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
 		SRpnt->sr_cmd_len = 0;
@@ -593,7 +602,7 @@
 	} else {
 #if 0
 		if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
-					 (long *) &scsi_CDs[i].capacity))
+					   &scsi_CDs[i].capacity))
 #endif
 			scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
 						    (buffer[1] << 16) |
@@ -656,8 +665,14 @@
 	};
 
 	buffer = (unsigned char *) scsi_malloc(512);
+	if (!buffer)
+	{
+		printk(KERN_ERR "sr: out of memory.\n");
+		return;
+	}
 	cmd[0] = MODE_SENSE;
-	cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+	cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
+		 ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
 	cmd[2] = 0x2a;
 	cmd[4] = 128;
 	cmd[3] = cmd[5] = 0;
@@ -734,7 +749,8 @@
 	Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
 
 	/* set the LUN */
-	cgc->cmd[1] |= device->lun << 5;
+	if (device->scsi_level <= SCSI_2)
+		cgc->cmd[1] |= device->lun << 5;
 
 	cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
 
@@ -775,16 +791,21 @@
 	if (!sr_blocksizes)
 		goto cleanup_sizes;
 
+	sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
+	if (!sr_hardsizes)
+		goto cleanup_blocksizes;
 	/*
 	 * These are good guesses for the time being.
-	 * Don't set sr_hardsizes here! That will prevent reading anything smaller.
 	 */
 	for (i = 0; i < sr_template.dev_max; i++) {
 		sr_blocksizes[i] = 2048;
+		sr_hardsizes[i] = 2048;
         }
 	blksize_size[MAJOR_NR] = sr_blocksizes;
+        hardsect_size[MAJOR_NR] = sr_hardsizes;
 	return 0;
-
+cleanup_blocksizes:
+	kfree(sr_blocksizes);
 cleanup_sizes:
 	kfree(sr_sizes);
 cleanup_cds:
@@ -830,6 +851,10 @@
 		scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i);
 		scsi_CDs[i].cdi.mask = 0;
 		scsi_CDs[i].cdi.capacity = 1;
+		/*
+		 *	FIXME: someone needs to handle a get_capabilities
+		 *	failure properly ??
+		 */
 		get_capabilities(i);
 		sr_vendor_init(i);
 
@@ -903,8 +928,11 @@
 
 		kfree(sr_blocksizes);
 		sr_blocksizes = NULL;
+		kfree(sr_hardsizes);
+		sr_hardsizes = NULL;
 	}
 	blksize_size[MAJOR_NR] = NULL;
+        hardsect_size[MAJOR_NR] = NULL;
 	blk_size[MAJOR_NR] = NULL;
 	read_ahead[MAJOR_NR] = 0;
 
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.4.6/linux/drivers/scsi/sr_ioctl.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/scsi/sr_ioctl.c	Thu Jul  5 11:28:17 2001
@@ -85,6 +85,10 @@
 
 	SDev = scsi_CDs[target].device;
 	SRpnt = scsi_allocate_request(scsi_CDs[target].device);
+        if (!SRpnt) {
+                printk("Unable to allocate SCSI request in sr_do_ioctl");
+                return -ENOMEM;
+        }
 	SRpnt->sr_data_direction = readwrite;
 
 	/* use ISA DMA buffer if necessary */
@@ -191,7 +195,8 @@
 	u_char sr_cmd[10];
 
 	sr_cmd[0] = GPCMD_TEST_UNIT_READY;
-	sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
+	sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[minor].device->lun) << 5) : 0;
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 	return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL);
 }
@@ -201,7 +206,8 @@
 	u_char sr_cmd[10];
 
 	sr_cmd[0] = GPCMD_START_STOP_UNIT;
-	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
 
@@ -273,7 +279,8 @@
 	int result;
 
 	sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
-	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
 	sr_cmd[2] = 0x40;	/* I do want the subchannel info */
 	sr_cmd[3] = 0x02;	/* Give me medium catalog number info */
 	sr_cmd[4] = sr_cmd[5] = 0;
@@ -307,7 +314,8 @@
 
 	memset(sr_cmd, 0, MAX_COMMAND_SIZE);
 	sr_cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
-	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
+	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+	            ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
 	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
 	sr_cmd[3] = speed & 0xff;	/* LSB */
 
@@ -336,7 +344,8 @@
 			struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
 
 			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
+			sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+			            ((scsi_CDs[target].device->lun) << 5) : 0;
 			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 			sr_cmd[8] = 12;		/* LSB of length */
 
@@ -353,8 +362,9 @@
 			struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
 
 			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
-			    (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
+			sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+			            ((scsi_CDs[target].device->lun) << 5) : 0;
+			sr_cmd[1] |= (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[8] = 12;		/* LSB of length */
@@ -379,7 +389,8 @@
 		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[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+		            (scsi_CDs[target].device->lun << 5) : 0;
 		sr_cmd[4] = ti->cdti_trk0;
 		sr_cmd[5] = ti->cdti_ind0;
 		sr_cmd[7] = ti->cdti_trk1;
@@ -429,7 +440,9 @@
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = GPCMD_READ_CD;	/* READ_CD */
-	cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
+	cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+	         (scsi_CDs[minor].device->lun << 5) : 0;
+	cmd[1] |= ((format & 7) << 2);
 	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
 	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
 	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
@@ -481,7 +494,8 @@
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = GPCMD_READ_10;
-	cmd[1] = (scsi_CDs[minor].device->lun << 5);
+	cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+	         (scsi_CDs[minor].device->lun << 5) : 0;
 	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
 	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
 	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
@@ -530,6 +544,8 @@
 	target = MINOR(cdi->dev);
 
 	switch (cmd) {
+	case BLKGETSIZE:
+		return put_user(scsi_CDs[target].capacity >> 1, (long *) arg);
 	case BLKROSET:
 	case BLKROGET:
 	case BLKRASET:
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.4.6/linux/drivers/scsi/sr_vendor.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/scsi/sr_vendor.c	Thu Jul  5 11:28:17 2001
@@ -124,7 +124,9 @@
 #endif
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = MODE_SELECT;
-	cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
+	cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+	         (scsi_CDs[minor].device->lun << 5) : 0;
+	cmd[1] |= (1 << 4);
 	cmd[4] = 12;
 	modesel = (struct ccs_modesel_head *) buffer;
 	memset(modesel, 0, sizeof(*modesel));
@@ -173,7 +175,8 @@
 	case VENDOR_SCSI3:
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_TOC;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+		         (scsi_CDs[minor].device->lun << 5) : 0;
 		cmd[8] = 12;
 		cmd[9] = 0x40;
 		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
@@ -198,7 +201,9 @@
 			unsigned long min, sec, frame;
 			memset(cmd, 0, MAX_COMMAND_SIZE);
 			cmd[0] = 0xde;
-			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
+			cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+			         (scsi_CDs[minor].device->lun << 5) : 0;
+			cmd[1] |= 0x03;
 			cmd[2] = 0xb0;
 			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
 			if (rc != 0)
@@ -223,7 +228,9 @@
 			 * where starts the last session ?) */
 			memset(cmd, 0, MAX_COMMAND_SIZE);
 			cmd[0] = 0xc7;
-			cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
+			cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+			         (scsi_CDs[minor].device->lun << 5) : 0;
+			cmd[1] |= 0x03;
 			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
 			if (rc == -EINVAL) {
 				printk(KERN_INFO "sr%d: Hmm, seems the drive "
@@ -246,7 +253,8 @@
 	case VENDOR_WRITER:
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_TOC;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+		         (scsi_CDs[minor].device->lun << 5) : 0;
 		cmd[8] = 0x04;
 		cmd[9] = 0x40;
 		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
@@ -259,7 +267,8 @@
 			break;
 		}
 		cmd[0] = READ_TOC;	/* Read TOC */
-		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+		         (scsi_CDs[minor].device->lun << 5) : 0;
 		cmd[6] = rc & 0x7f;	/* number of last session */
 		cmd[8] = 0x0c;
 		cmd[9] = 0x40;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.4.6/linux/drivers/scsi/st.c	Sat Dec 30 11:23:14 2000
+++ linux/drivers/scsi/st.c	Thu Jul  5 11:28:17 2001
@@ -359,7 +359,8 @@
 		}
 	}
 
-	cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
+	if (SRpnt->sr_device->scsi_level <= SCSI_2)
+		cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
 	init_MUTEX_LOCKED(&STp->sem);
 	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
 	    (STp->buffer)->use_sg : 0;
@@ -3495,7 +3496,7 @@
 	Scsi_Tape *tpnt;
 	ST_mode *STm;
 	ST_partstat *STps;
-	int i, mode, target_nbr;
+	int i, mode, target_nbr, dev_num;
 	unsigned long flags = 0;
 	char *stp;
 
@@ -3573,6 +3574,7 @@
 	}
 	memset(tpnt, 0, sizeof(Scsi_Tape));
 	scsi_tapes[i] = tpnt;
+	dev_num = i;
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
 	    char name[8];
@@ -3653,6 +3655,9 @@
 
 	st_template.nr_dev++;
 	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	printk(KERN_WARNING
+	"Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
+	       dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 
 	/* See if we need to allocate more static buffers */
 	target_nbr = st_template.nr_dev;
@@ -3673,12 +3678,7 @@
 {
 	if (SDp->type != TYPE_TAPE || st_incompatible(SDp))
 		return 0;
-
-	printk(KERN_WARNING
-	"Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
-	       st_template.dev_noticed++,
-	       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+        st_template.dev_noticed++;
 	return 1;
 }
 
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.4.6/linux/drivers/scsi/sym53c8xx.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/scsi/sym53c8xx.c	Thu Jul  5 11:28:16 2001
@@ -85,7 +85,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx-1.7.3a-20010304"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx-1.7.3c-20010512"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -584,6 +584,9 @@
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 #define pci_enable_device(pdev)		(0)
 #endif
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+#define	scsi_set_pci_device(inst, pdev)	(0)
+#endif
 
 /*==========================================================
 **
@@ -3781,7 +3784,7 @@
 		SIR_MSG_RECEIVED,
 
 }/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
-	SCR_LOAD_REL (scratcha1, 4),	/* DUMMY READ */
+	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
 		0,
 	SCR_INT,
 		SIR_MSG_WEIRD,
@@ -6591,7 +6594,7 @@
 	**
 	**----------------------------------------------------
 	*/
-#if 0	/* This stuff was only usefull for linux-1.2.13 */
+#if 0	/* This stuff was only useful for linux-1.2.13 */
 	if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
 		lp->numtags = tp->usrtags;
 		ncr_setup_tags (np, cp->target, cp->lun);
@@ -6991,22 +6994,26 @@
 	u_char istat;
 	int i;
 
+	if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN))
+		goto do_chip_reset;
+
 	OUTB (nc_istat, CABRT);
-	for (i = 1000000 ; i ; --i) {
+	for (i = 100000 ; i ; --i) {
 		istat = INB (nc_istat);
 		if (istat & SIP) {
 			INW (nc_sist);
-			continue;
 		}
-		if (istat & DIP) {
-			OUTB (nc_istat, 0);
-			INB (nc_dstat);
-			break;
+		else if (istat & DIP) {
+			if (INB (nc_dstat) & ABRT);
+				break;
 		}
+		UDELAY(5);
 	}
+	OUTB (nc_istat, 0);
 	if (!i)
-		printk("%s: unable to abort current chip operation.\n",
-			ncr_name(np));
+		printk("%s: unable to abort current chip operation, "
+		       "ISTAT=0x%02x.\n", ncr_name(np), istat);
+do_chip_reset:
 	ncr_chip_reset(np);
 }
 
@@ -7419,10 +7426,10 @@
 		/*
 		**	On standard INQUIRY response (EVPD and CmDt 
 		**	not set), setup logical unit according to 
-		**	announced capabilities (we need the 1rst 7 bytes).
+		**	announced capabilities (we need the 1rst 8 bytes).
 		*/
 		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
-		    cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+		    cmd->request_bufflen - cp->resid > 7 && !cmd->use_sg) {
 			sync_scsi_data(np, cmd);	/* SYNC the data */
 			ncr_setup_lcb (np, cp->target, cp->lun,
 				       (char *) cmd->request_buffer);
@@ -7959,7 +7966,7 @@
 	*/
 	fak = (kpc - 1) / div_10M[div] + 1;
 
-#if 0	/* This optimization does not seem very usefull */
+#if 0	/* This optimization does not seem very useful */
 
 	per = (fak * div_10M[div]) / clk;
 
@@ -8685,7 +8692,7 @@
 **		scntl3:	(see the manual)
 **
 **	current script command:
-**		dsp:	script adress (relative to start of script).
+**		dsp:	script address (relative to start of script).
 **		dbc:	first word of script command.
 **
 **	First 24 register of the chip:
@@ -9535,7 +9542,7 @@
 
 #ifdef  SYM_DEBUG_PM_WITH_WSR
 		PRINT_ADDR(cp);
-		printf ("MA interrupt with WSR set - "
+		printk ("MA interrupt with WSR set - "
 			"pm->sg.addr=%x - pm->sg.size=%d\n",
 			pm->sg.addr, pm->sg.size);
 #endif
@@ -10167,14 +10174,16 @@
 				if (i >= MAX_START*2)
 					i = 0;
 			}
-			assert(k != -1);
-			if (k != 1) {
+			/*
+			**	If job removed, repair the start queue.
+			*/
+			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);
 			}
+			cp->host_status = HS_ABORTED;
+			cp->scsi_status = S_ILLEGAL;
+			ncr_complete(np, cp);
 		}
 		break;
 	/*
@@ -10730,7 +10739,7 @@
 **	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
+**	a successful inquire command. We look at byte 7 of the
 **	inquire data to determine the capabilities of the target.
 **
 **	When we try to negotiate, we append the negotiation message
@@ -11571,7 +11580,7 @@
 /*==========================================================
 **
 **
-**	Aquire a control block
+**	Acquire a control block
 **
 **
 **==========================================================
@@ -12223,6 +12232,7 @@
 static int __init ncr_snooptest (struct ncb* np)
 {
 	u_int32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+	u_char  dstat;
 	int	i, err=0;
 #ifndef SCSI_NCR_IOMAPPED
 	if (np->reg) {
@@ -12230,6 +12240,12 @@
             if (err) return (err);
 	}
 #endif
+restart_test:
+	/*
+	**	Enable Master Parity Checking as we intend 
+	**	to enable it for normal operations.
+	*/
+	OUTB (nc_ctest4, (np->rv_ctest4 & MPEE));
 	/*
 	**	init
 	*/
@@ -12252,6 +12268,27 @@
 	for (i=0; i<NCR_SNOOP_TIMEOUT; i++)
 		if (INB(nc_istat) & (INTF|SIP|DIP))
 			break;
+	if (i>=NCR_SNOOP_TIMEOUT) {
+		printk ("CACHE TEST FAILED: timeout.\n");
+		return (0x20);
+	};
+	/*
+	**	Check for fatal DMA errors.
+	*/
+	dstat = INB (nc_dstat);
+#if 1	/* Band aiding for broken hardwares that fail PCI parity */
+	if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) {
+		printk ("%s: PCI DATA PARITY ERROR DETECTED - "
+			"DISABLING MASTER DATA PARITY CHECKING.\n",
+			ncr_name(np));
+		np->rv_ctest4 &= ~MPEE;
+		goto restart_test;
+	}
+#endif
+	if (dstat & (MDPE|BF|IID)) {
+		printk ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat);
+		return (0x80);
+	}
 	/*
 	**	Save termination position.
 	*/
@@ -12262,14 +12299,6 @@
 	host_rd = scr_to_cpu(np->ncr_cache);
 	ncr_rd  = INL (nc_scratcha);
 	ncr_bk  = INL (nc_temp);
-
-	/*
-	**	check for timeout
-	*/
-	if (i>=NCR_SNOOP_TIMEOUT) {
-		printk ("CACHE TEST FAILED: timeout.\n");
-		return (0x20);
-	};
 	/*
 	**	Check termination position.
 	*/
@@ -14381,7 +14410,7 @@
 	/* save current state of GPCNTL and GPREG */
 	old_gpreg	= INB (nc_gpreg);
 	old_gpcntl	= INB (nc_gpcntl);
-	gpcntl		= old_gpcntl & 0xfc;
+	gpcntl		= old_gpcntl & 0x1c;
 
 	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
 	OUTB (nc_gpreg,  old_gpreg);
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.4.6/linux/drivers/scsi/sym53c8xx_comm.h	Tue Mar  6 19:34:25 2001
+++ linux/drivers/scsi/sym53c8xx_comm.h	Thu Jul  5 11:28:16 2001
@@ -403,6 +403,9 @@
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 #define pci_enable_device(pdev)		(0)
 #endif
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+#define	scsi_set_pci_device(inst, pdev)	(0)
+#endif
 
 /*==========================================================
 **
@@ -1311,7 +1314,7 @@
 	/* save current state of GPCNTL and GPREG */
 	old_gpreg	= INB (nc_gpreg);
 	old_gpcntl	= INB (nc_gpcntl);
-	gpcntl		= old_gpcntl & 0xfc;
+	gpcntl		= old_gpcntl & 0x1c;
 
 	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
 	OUTB (nc_gpreg,  old_gpreg);
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- v2.4.6/linux/drivers/scsi/sym53c8xx_defs.h	Fri May 25 18:02:55 2001
+++ linux/drivers/scsi/sym53c8xx_defs.h	Mon Jul  9 11:42:31 2001
@@ -168,16 +168,17 @@
 #endif
 
 /*
- * Use normal IO if configured. Forced for alpha and powerpc.
- * Powerpc fails copying to on-chip RAM using memcpy_toio().
+ * Use normal IO if configured. Forced for alpha.
  */
 #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
 #define	SCSI_NCR_IOMAPPED
 #elif defined(__alpha__)
 #define	SCSI_NCR_IOMAPPED
 #elif defined(__powerpc__)
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,3)
 #define	SCSI_NCR_IOMAPPED
 #define SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+#endif
 #elif defined(__sparc__)
 #undef SCSI_NCR_IOMAPPED
 #endif
@@ -734,7 +735,7 @@
 #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_VARCLK	(1<<15)   /* SCSI lock may vary */
+#define FE_VARCLK	(1<<15)   /* SCSI clock may vary */
 #define FE_RAM8K	(1<<16)   /* On chip RAM sized 8Kb */
 #define FE_64BIT	(1<<17)   /* Have a 64-bit PCI interface */
 #define FE_IO256	(1<<18)   /* Requires full 256 bytes in PCI space */
@@ -744,6 +745,7 @@
 #define FE_ULTRA3	(1<<22)   /* Ultra-3 80Mtrans/sec */
 #define FE_66MHZ 	(1<<23)   /* 66MHz PCI Support */
 #define FE_DAC	 	(1<<24)   /* Support DAC cycles (64 bit addressing) */
+#define FE_ISTAT1 	(1<<25)   /* Have ISTAT1, MBOX0, MBOX1 registers */
 
 #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)
@@ -808,7 +810,7 @@
  ,									\
  {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_DAC|FE_IO256|FE_NOPM|FE_LEDC}		\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ISTAT1}	\
  ,									\
  {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|	\
@@ -823,11 +825,11 @@
  FE_RAM|FE_IO256}							\
  ,									\
  {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33",  6, 62, 7,		\
- FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|		\
+ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1|	\
  FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|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_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1|	\
  FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3|	\
  FE_66MHZ}								\
 }
@@ -1179,9 +1181,13 @@
         #define   SIP     0x02  /* sta: scsi-interrupt              */
         #define   DIP     0x01  /* sta: host/script interrupt       */
 
-/*15*/  u_char    nc_istat1;	/* 896 only */
-/*16*/  u_char    nc_mbox0;	/* 896 only */
-/*17*/  u_char    nc_mbox1;	/* 896 only */
+/*15*/  u_char    nc_istat1;	/* 896 and later cores only */
+        #define   FLSH    0x04  /* sta: chip is flushing            */
+        #define   SRUN    0x02  /* sta: scripts are running         */
+        #define   SIRQD   0x01  /* r/w: disable INT pin             */
+
+/*16*/  u_char    nc_mbox0;	/* 896 and later cores only */
+/*17*/  u_char    nc_mbox1;	/* 896 and later cores only */
 
 /*18*/	u_char	  nc_ctest0;
 /*19*/  u_char    nc_ctest1;
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v2.4.6/linux/drivers/scsi/ultrastor.c	Sat Feb  3 11:32:54 2001
+++ linux/drivers/scsi/ultrastor.c	Wed Jul  4 11:50:39 2001
@@ -259,7 +259,7 @@
 } config = {0};
 
 /* Set this to 1 to reset the SCSI bus on error.  */
-int ultrastor_bus_reset = 0;
+int ultrastor_bus_reset;
 
 
 /* Allowed BIOS base addresses (NULL indicates reserved) */
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.4.6/linux/drivers/sound/Config.in	Tue Jul  3 17:08:21 2001
+++ linux/drivers/sound/Config.in	Wed Jul  4 11:50:38 2001
@@ -6,12 +6,27 @@
 
 # Prompt user for primary drivers.
 
-dep_tristate '  C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI
+dep_tristate '  C-Media PCI (CMI8338/8738)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
-    bool '    Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP
-    bool '    Enable 4 channel mode for CMI8738' CONFIG_SOUND_CMPCI_4CH
-    if [ "$CONFIG_SOUND_CMPCI_4CH" = "y" ]; then
-        bool '    Separate rear out jack' CONFIG_SOUND_CMPCI_REAR
+    bool '    Enable legacy FM' CONFIG_SOUND_CMPCI_FM
+    if [ "$CONFIG_SOUND_CMPCI_FM" = "y" ]; then
+	define_hex CONFIG_SOUND_CMPCI_FMIO 388
+        hex '    FM I/O 388, 3C8, 3E0, 3E8' CONFIG_SOUND_CMPCI_FMIO 388
+    fi
+    bool '    Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI
+    if [ "$CONFIG_SOUND_CMPCI_MIDI" = "y" ]; then
+        hex '    MPU-401 I/O 330, 320, 310, 300' CONFIG_SOUND_CMPCI_MPUIO 330
+    fi
+    bool '    Enable joystick' CONFIG_SOUND_CMPCI_JOYSTICK
+    bool '    Support CMI8738 based audio cards' CONFIG_SOUND_CMPCI_CM8738
+    if [ "$CONFIG_SOUND_CMPCI_CM8738" = "y" ]; then
+	bool '      Inverse S/PDIF in for CMI8738' CONFIG_SOUND_CMPCI_SPDIFINVERSE
+	bool '      Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP
+	int  '      Number of speakers 2, 4, 5, 6' CONFIG_SOUND_CMPCI_SPEAKERS 2
+	if [ "$CONFIG_SOUND_CMPCI_SPEAKERS" != "2" ]; then
+	    bool '        Use Line-in as Read-out' CONFIG_SOUND_CMPCI_LINE_REAR
+	    bool '        Use Line-in as Bass' CONFIG_SOUND_CMPCI_LINE_BASS
+	fi
     fi
 fi
 dep_tristate '  Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND $CONFIG_PCI
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.4.6/linux/drivers/sound/ad1848.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/ad1848.c	Wed Jul  4 11:50:39 2001
@@ -106,11 +106,11 @@
 ad1848_port_info;
 
 static struct address_info cfg;
-static int nr_ad1848_devs = 0;
+static int nr_ad1848_devs;
 
-int deskpro_xl = 0;
-int deskpro_m = 0;
-int soundpro = 0;
+int deskpro_xl;
+int deskpro_m;
+int soundpro;
 
 static volatile signed char irq2dev[17] = {
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -121,7 +121,7 @@
 static int timer_installed = -1;
 #endif
 
-static int loaded = 0;
+static int loaded;
 
 static int ad_format_mask[10 /*devc->model */ ] =
 {
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.4.6/linux/drivers/sound/dev_table.h	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/dev_table.h	Wed Jul  4 11:50:39 2001
@@ -350,14 +350,14 @@
 };
 
 #ifdef _DEV_TABLE_C_   
-struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL};
-int num_audiodevs = 0;
-struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL};
-int num_mixers = 0;
-struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL};
-int num_synths = 0;
-struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL};
-int num_midis = 0;
+struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+int num_audiodevs;
+struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+int num_mixers;
+struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
+int num_synths;
+struct midi_operations *midi_devs[MAX_MIDI_DEV];
+int num_midis;
 
 extern struct sound_timer_operations default_sound_timer;
 struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.4.6/linux/drivers/sound/maestro.c	Fri Mar  2 11:12:11 2001
+++ linux/drivers/sound/maestro.c	Wed Jul  4 11:50:39 2001
@@ -115,6 +115,12 @@
  *	themselves, but we'll see.  
  *	
  * History
+ *  v0.15 - May 21 2001 - Marcus Meissner <mm@caldera.de>
+ *      Ported to Linux 2.4 PCI API. Some clean ups, global devs list
+ *      removed (now using pci device driver data).
+ *      PM needs to be polished still. Bumped version.
+ *  (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben@msu.edu>
+ *      Add support for 978 docking and basic hardware volume control
  *  (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com>
  *	Add clocking= for people with seriously warped hardware
  *  (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
@@ -189,7 +195,7 @@
  *	fix bob frequency
  *	endianness
  *	do smart things with ac97 2.0 bits.
- *	docking and dual codecs and 978?
+ *	dual codecs
  *	leave 54->61 open
  *
  *	it also would be fun to have a mode that would not use pci dma at all
@@ -204,28 +210,6 @@
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/wrapper.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-
- #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)
-
-
-#else
-
- #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start)
- #define SILLY_INIT_SEM(SEM) init_MUTEX(&SEM)
- #define SILLY_MAKE_INIT(FUNC) __init FUNC
- #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff)
-
-
-#endif
-
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/ioport.h>
@@ -249,6 +233,8 @@
 
 #include "maestro.h"
 
+static struct pci_driver maestro_pci_driver;
+
 /* --------------------------------------------------------------------- */
 
 #define M_DEBUG 1
@@ -269,8 +255,17 @@
 	
 static int clocking=48000;
 
+MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>");
+MODULE_DESCRIPTION("ESS Maestro Driver");
+#ifdef M_DEBUG
+MODULE_PARM(debug,"i");
+#endif
+MODULE_PARM(dsps_order,"i");
+MODULE_PARM(use_pm,"i");
+MODULE_PARM(clocking, "i");
+
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.14"
+#define DRIVER_VERSION "0.15"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS			0x125D
@@ -352,6 +347,11 @@
 	[ACPI_D3] = ACPI_NONE
 };
 
+static char version[] __devinitdata =
+KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n";
+
+
+
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
@@ -483,8 +483,12 @@
 
 	int bob_freq;
 	char dsps_open;
+
+	int dock_mute_vol;
 };
 
+static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val );
+
 static unsigned 
 ld2(unsigned int x)
 {
@@ -516,8 +520,6 @@
 
 static void check_suspend(struct ess_card *card);
 
-static struct ess_card *devs = NULL;
-
 /* --------------------------------------------------------------------- */
 
 
@@ -983,6 +985,17 @@
 		outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
 		outw(0x0209, ioaddr + 0x60);
 	}
+
+	/* Turn on the 978 docking chip.
+	   First frob the "master output enable" bit,
+	   then set most of the playback volume control registers to max. */
+	outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);
+	outb(0xff, ioaddr+0xc3);
+	outb(0xff, ioaddr+0xc4);
+	outb(0xff, ioaddr+0xc6);
+	outb(0xff, ioaddr+0xc8);
+	outb(0x3f, ioaddr+0xcf);
+	outb(0x3f, ioaddr+0xd0);
 }
 /*
  *	Indirect register access. Not all registers are readable so we
@@ -1895,19 +1908,52 @@
 	outw(inw(c->iobase+4)&1, c->iobase+4);
 
 /*	M_printk("maestro int: %x\n",event);*/
-
 	if(event&(1<<6))
 	{
-		/* XXX if we have a hw volume control int enable
-			all the ints?  doesn't make sense.. */
-		event = inw(c->iobase+0x18);
-		outb(0xFF, c->iobase+0x1A);
-	}
-	else
-	{
-		/* else ack 'em all, i imagine */
-		outb(0xFF, c->iobase+0x1A);
+		int x;
+		enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;
+		int volume;
+
+		/* Figure out which volume control button was pushed,
+		   based on differences from the default register
+		   values. */
+		x = inb(c->iobase+0x1c);
+		if (x&1) vol_evt = MUTE_EVT;
+		else if (((x>>1)&7) > 4) vol_evt = UP_EVT;
+		else vol_evt = DOWN_EVT;
+
+		/* Reset the volume control registers. */
+		outb(0x88, c->iobase+0x1c);
+		outb(0x88, c->iobase+0x1d);
+		outb(0x88, c->iobase+0x1e);
+		outb(0x88, c->iobase+0x1f);
+
+		/* Deal with the button press in a hammer-handed
+		   manner by adjusting the master mixer volume. */
+		volume = c->mix.mixer_state[0] & 0xff;
+		if (vol_evt == UP_EVT) {
+			volume += 10;
+			if (volume > 100)
+				volume = 100;
+		}
+		else if (vol_evt == DOWN_EVT) {
+			volume -= 10;
+			if (volume < 0)
+				volume = 0;
+		} else {
+			/* vol_evt == MUTE_EVT */
+			if (volume == 0)
+				volume = c->dock_mute_vol;
+			else {
+				c->dock_mute_vol = volume;
+				volume = 0;
+			}
+		}
+		set_mixer (c, 0, (volume << 8) | volume);
 	}
+
+	/* Ack all the interrupts. */
+	outb(0xFF, c->iobase+0x1A);
 		
 	/*
 	 *	Update the pointers for all APU's we are running.
@@ -2083,17 +2129,25 @@
 }
 
 /* --------------------------------------------------------------------- */
-
 static int ess_open_mixdev(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct ess_card *card = devs;
-
-	while (card && card->dev_mixer != minor)
-		card = card->next;
+	struct ess_card *card = NULL;
+	struct pci_dev *pdev;
+	struct pci_driver *drvr;
+
+	pci_for_each_dev(pdev) {
+		drvr = pci_dev_driver (pdev);
+		if (drvr == &maestro_pci_driver) {
+			card = (struct ess_card*)pci_get_drvdata (pdev);
+			if (!card)
+				continue;
+			if (card->dev_mixer == minor)
+				break;
+		}
+	}
 	if (!card)
 		return -ENODEV;
-
 	file->private_data = card;
 	return 0;
 }
@@ -2455,7 +2509,7 @@
 #endif
 		goto out;
 	ret = -EINVAL;
-	if (SILLY_OFFSET(vma) != 0)
+	if (vma->vm_pgoff != 0)
 		goto out;
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << db->buforder))
@@ -2919,33 +2973,40 @@
 ess_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct ess_card *c = devs;
-	struct ess_state *s = NULL, *sp;
-	int i;
+	struct ess_state *s = NULL;
 	unsigned char fmtm = ~0, fmts = 0;
-
+	struct pci_dev *pdev;
 	/*
 	 *	Scan the cards and find the channel. We only
 	 *	do this at open time so it is ok
 	 */
-	 
-	while (c!=NULL)
-	{
-		for(i=0;i<NR_DSPS;i++)
-		{
-			sp=&c->channels[i];
-			if(sp->dev_audio < 0)
-				continue;
-			if((sp->dev_audio ^ minor) & ~0xf)
+
+	pci_for_each_dev(pdev) {
+		struct ess_card *c;
+		struct pci_driver *drvr;
+
+		drvr = pci_dev_driver (pdev);
+		if (drvr == &maestro_pci_driver) {
+			int i;
+			struct ess_state *sp;
+
+			c = (struct ess_card*)pci_get_drvdata (pdev);
+			if (!c)
 				continue;
-			s=sp;
+			for(i=0;i<NR_DSPS;i++)
+			{
+				sp=&c->channels[i];
+				if(sp->dev_audio < 0)
+					continue;
+				if((sp->dev_audio ^ minor) & ~0xf)
+					continue;
+				s=sp;
+			}
 		}
-		c=c->next;
 	}
-		
 	if (!s)
 		return -ENODEV;
-		
+
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
@@ -3087,8 +3148,8 @@
 	/* XXX how do we know which to use? */
 	w&=~(1<<14);		/* External clock */
 	
-	w&=~(1<<7);		/* HWV off */
-	w&=~(1<<6);		/* Debounce off */
+	w|= (1<<7);		/* Hardware volume control on */
+	w|= (1<<6);		/* Debounce off: easier to push the HWV buttons. */
 	w&=~(1<<5);		/* GPIO 4:5 */
 	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
 	w&=~(1<<2);		/* MIDI fix off (undoc) */
@@ -3106,6 +3167,12 @@
 	 
 	pci_write_config_word(pcidev, 0x40, w);
 
+	/* Set up 978 docking control chip. */
+	pci_read_config_word(pcidev, 0x58, &w);
+	w|=1<<2;	/* Enable 978. */
+	w|=1<<3;	/* Turn on 978 hardware volume control. */
+	w&=~(1<<11);	/* Turn on 978 mixer volume control. */
+	pci_write_config_word(pcidev, 0x58, w);
 	
 	sound_reset(iobase);
 
@@ -3170,7 +3237,7 @@
 	outw(w, iobase+0x18);
 
 	w=inw(iobase+0x18);
-	w&=~(1<<6);		/* Harpo off */
+	w&=~(1<<6);		/* Hardware volume control interrupt off... for now. */
 	outw(w, iobase+0x18);
 	
 	w=inw(iobase+0x18);
@@ -3193,6 +3260,13 @@
 	w|=(1<<0);		/* SB IRQ on */
 	outw(w, iobase+0x18);
 
+	/* Set hardware volume control registers to midpoints.
+	   We can tell which button was pushed based on how they change. */
+	outb(0x88, iobase+0x1c);
+	outb(0x88, iobase+0x1d);
+	outb(0x88, iobase+0x1e);
+	outb(0x88, iobase+0x1f);
+
 	/* it appears some maestros (dell 7500) only work if these are set,
 		regardless of wether we use the assp or not. */
 
@@ -3308,32 +3382,44 @@
 }
 
 static int __init
-maestro_install(struct pci_dev *pcidev, int card_type)
+maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid)
 {
+	int card_type = pdid->driver_data;
 	u32 n;
 	int iobase;
-	int i;
+	int i, ret;
 	struct ess_card *card;
 	struct ess_state *ess;
 	struct pm_dev *pmdev;
 	int num = 0;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
 	/* don't pick up weird modem maestros */
 	if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
-		return 0;
+		return -ENODEV;
+
+
+	if ((ret=pci_enable_device(pcidev)))
+		return ret;
 			
-	iobase = SILLY_PCI_BASE_ADDRESS(pcidev); 
+	iobase = pci_resource_start(pcidev,0);
+	if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO))
+		return -ENODEV;
+
+	if(pcidev->irq == 0)
+		return -ENODEV;
 
 	/* stake our claim on the iospace */
 	if( request_region(iobase, 256, card_names[card_type]) == NULL )
 	{
 		printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
-		return 0;
-	}
-
-	/* this was tripping up some machines */
-	if(pcidev->irq == 0) {
-		printk(KERN_WARNING "maestro: pci subsystem reports irq 0, this might not be correct.\n");
+		return -EBUSY;
 	}
 
 	/* just to be sure */
@@ -3343,7 +3429,8 @@
 	if(card == NULL)
 	{
 		printk(KERN_WARNING "maestro: out of memory\n");
-		return 0;
+		release_region(iobase, 256);
+		return -ENOMEM;
 	}
 	
 	memset(card, 0, sizeof(*card));
@@ -3354,18 +3441,14 @@
 	if (pmdev)
 		pmdev->data = card;
 
-	if (register_reboot_notifier(&maestro_nb)) {
-		printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
-	}
-
 	card->iobase = iobase;
 	card->card_type = card_type;
 	card->irq = pcidev->irq;
-	card->next = devs;
 	card->magic = ESS_CARD_MAGIC;
 	spin_lock_init(&card->lock);
 	init_waitqueue_head(&card->suspend_queue);
-	devs = card;
+
+	card->dock_mute_vol = 50;
 	
 	/* init our groups of 6 apus */
 	for(i=0;i<NR_DSPS;i++)
@@ -3379,7 +3462,7 @@
 		init_waitqueue_head(&s->dma_dac.wait);
 		init_waitqueue_head(&s->open_wait);
 		spin_lock_init(&s->lock);
-		SILLY_INIT_SEM(s->open_sem);
+		init_MUTEX(&s->open_sem);
 		s->magic = ESS_STATE_MAGIC;
 		
 		s->apu[0] = 6*i;
@@ -3407,19 +3490,6 @@
 	
 	ess = &card->channels[0];
 
-	if (pci_enable_device(pcidev)) {
-		printk (KERN_ERR "maestro: pci_enable_device() failed\n");
-		for (i = 0; i < NR_DSPS; i++) {
-			struct ess_state *s = &card->channels[i];
-			if (s->dev_audio != -1)
-				unregister_sound_dsp(s->dev_audio);
-		}
-		release_region(card->iobase, 256);
-		unregister_reboot_notifier(&maestro_nb);
-		kfree(card);
-		return 0;
-	}
-
 	/*
 	 *	Ok card ready. Begin setup proper
 	 */
@@ -3469,7 +3539,7 @@
 		mixer_push_state(card);
 	}
 	
-	if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card))
+	if((ret=request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card)))
 	{
 		printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
 		unregister_sound_mixer(card->dev_mixer);
@@ -3482,26 +3552,69 @@
 		release_region(card->iobase, 256);		
 		unregister_reboot_notifier(&maestro_nb);
 		kfree(card);
-		return 0;
+		return ret;
 	}
+
+	/* Turn on hardware volume control interrupt.
+	   This has to come after we grab the IRQ above,
+	   or a crash will result on installation if a button has been pressed,
+	   because in that case we'll get an immediate interrupt. */
+	n = inw(iobase+0x18);
+	n|=(1<<6);
+	outw(n, iobase+0x18);
+
+	pci_set_drvdata(pcidev,card);
 	/* now go to sleep 'till something interesting happens */
 	maestro_power(card,ACPI_D2);
 
 	printk(KERN_INFO "maestro: %d channels configured.\n", num);
-	return 1; 
+	return 0;
 }
 
-int __init init_maestro(void)
-{
-	struct pci_dev *pcidev = NULL;
-	int foundone = 0;
-
-	if (!pci_present())   /* No PCI bus in this machine! */
-		return -ENODEV;
-	printk(KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n");
+static void maestro_remove(struct pci_dev *pcidev) {
+	struct ess_card *card = pci_get_drvdata(pcidev);
+	int i;
+	
+	/* XXX maybe should force stop bob, but should be all 
+		stopped by _release by now */
+	free_irq(card->irq, card);
+	unregister_sound_mixer(card->dev_mixer);
+	for(i=0;i<NR_DSPS;i++)
+	{
+		struct ess_state *ess = &card->channels[i];
+		if(ess->dev_audio != -1)
+			unregister_sound_dsp(ess->dev_audio);
+	}
+	/* Goodbye, Mr. Bond. */
+	maestro_power(card,ACPI_D3);
+ 	release_region(card->iobase, 256);
+	kfree(card);
+	pci_set_drvdata(pcidev,NULL);
+}
+
+static struct pci_device_id maestro_pci_tbl[] __devinitdata = {
+	{PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2},
+	{PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E},
+	{PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, maestro_pci_tbl);
 
-	pcidev = NULL;
+static struct pci_driver maestro_pci_driver = {
+	name:"maestro",
+	id_table:maestro_pci_tbl,
+	probe:maestro_probe,
+	remove:maestro_remove,
+};
 
+int __init init_maestro(void)
+{
+	pci_module_init(&maestro_pci_driver);
+	if (register_reboot_notifier(&maestro_nb))
+		printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
+#ifdef MODULE
+	printk(version);
+#endif
 	if (dsps_order < 0)   {
 		dsps_order = 1;
 		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
@@ -3510,97 +3623,29 @@
 		dsps_order = MAX_DSP_ORDER;
 		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
 	}
-
-	/*
-	 *	Find the ESS Maestro 2.
-	 */
-
-	while( (pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL ) {
-		if (maestro_install(pcidev, TYPE_MAESTRO2))
-			foundone=1;
-	}
-
-	/*
-	 *	Find the ESS Maestro 2E
-	 */
-
-	while( (pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) {
-		if (maestro_install(pcidev, TYPE_MAESTRO2E))
-			foundone=1;
-	}
-
-	/*
-	 *	ESS Maestro 1
-	 */
-
-	while((pcidev = pci_find_device(PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, pcidev))!=NULL) {
-		if (maestro_install(pcidev, TYPE_MAESTRO))
-			foundone=1;
-	}
-	if( ! foundone ) {
-		printk("maestro: no devices found.\n");
-		return -ENODEV;
-	}
 	return 0;
 }
 
-static void nuke_maestros(void)
-{
-	struct ess_card *card;
-
-	/* we do these unconditionally, which is probably wrong */
-	pm_unregister_all(maestro_pm_callback);
-	unregister_reboot_notifier(&maestro_nb);
-
-	while ((card = devs)) {
-		int i;
-		devs = devs->next;
-	
-		/* XXX maybe should force stop bob, but should be all 
-			stopped by _release by now */
-		free_irq(card->irq, card);
-		unregister_sound_mixer(card->dev_mixer);
-		for(i=0;i<NR_DSPS;i++)
-		{
-			struct ess_state *ess = &card->channels[i];
-			if(ess->dev_audio != -1)
-				unregister_sound_dsp(ess->dev_audio);
-		}
-		/* Goodbye, Mr. Bond. */
-		maestro_power(card,ACPI_D3);
-		release_region(card->iobase, 256);
-		kfree(card);
-	}
-	devs = NULL;
-}
-
 static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
 {
 	/* this notifier is called when the kernel is really shut down. */
 	M_printk("maestro: shutting down\n");
-	nuke_maestros();
+	/* this will remove all card instances too */
+	pci_unregister_driver(&maestro_pci_driver);
+	/* XXX dunno about power management */
 	return NOTIFY_OK;
 }
 
 /* --------------------------------------------------------------------- */
 
-#ifdef MODULE
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("ESS Maestro Driver");
-#ifdef M_DEBUG
-MODULE_PARM(debug,"i");
-#endif
-MODULE_PARM(dsps_order,"i");
-MODULE_PARM(use_pm,"i");
-MODULE_PARM(clocking, "i");
 
-void cleanup_module(void) {
+void cleanup_maestro(void) {
 	M_printk("maestro: unloading\n");
-	nuke_maestros();
+	pci_unregister_driver(&maestro_pci_driver);
+	pm_unregister_all(maestro_pm_callback);
+	unregister_reboot_notifier(&maestro_nb);
 }
 
-#endif
-
 /* --------------------------------------------------------------------- */
 
 void
@@ -3759,3 +3804,4 @@
 }
 
 module_init(init_maestro);
+module_exit(cleanup_maestro);
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c
--- v2.4.6/linux/drivers/sound/nm256_audio.c	Tue May  1 16:05:00 2001
+++ linux/drivers/sound/nm256_audio.c	Wed Jul  4 11:50:39 2001
@@ -29,8 +29,8 @@
 #include "nm256.h"
 #include "nm256_coeff.h"
 
-int nm256_debug = 0;
-static int force_load = 0;
+int nm256_debug;
+static int force_load;
 
 /* 
  * The size of the playback reserve.  When the playback buffer has less
@@ -131,8 +131,8 @@
     return NULL;
 }
 
-static int usecache = 0;
-static int buffertop = 0;
+static int usecache;
+static int buffertop;
 
 /* Check to see if we're using the bank of cached coefficients. */
 int
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.4.6/linux/drivers/sound/sb_common.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/sound/sb_common.c	Wed Jul  4 11:50:39 2001
@@ -45,10 +45,10 @@
  * global module flag
  */
 
-int sb_be_quiet = 0;
+int sb_be_quiet;
 
-static sb_devc *detected_devc = NULL;	/* For communication from probe to init */
-static sb_devc *last_devc = NULL;	/* For MPU401 initialization */
+static sb_devc *detected_devc;	/* For communication from probe to init */
+static sb_devc *last_devc;	/* For MPU401 initialization */
 
 static unsigned char jazz_irq_bits[] = {
 	0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6
@@ -58,14 +58,14 @@
 	0, 1, 0, 2, 0, 3, 0, 4
 };
 
-void *smw_free = NULL;
+void *smw_free;
 
 /*
  * Jazz16 chipset specific control variables
  */
 
-static int jazz16_base = 0;		/* Not detected */
-static unsigned char jazz16_bits = 0;	/* I/O relocation bits */
+static int jazz16_base;			/* Not detected */
+static unsigned char jazz16_bits;	/* I/O relocation bits */
 static spinlock_t jazz16_lock = SPIN_LOCK_UNLOCKED;
 
 /*
@@ -75,12 +75,12 @@
 #ifdef SMW_MIDI0001_INCLUDED
 #include "smw-midi0001.h"
 #else
-static unsigned char *smw_ucode = NULL;
-static int      smw_ucodeLen = 0;
+static unsigned char *smw_ucode;
+static int      smw_ucodeLen;
 
 #endif
 
-sb_devc *last_sb = NULL;		/* Last sb loaded */
+sb_devc *last_sb;		/* Last sb loaded */
 
 int sb_dsp_command(sb_devc * devc, unsigned char val)
 {
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- v2.4.6/linux/drivers/sound/ymfpci.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/sound/ymfpci.c	Wed Jul  4 11:50:39 2001
@@ -23,14 +23,9 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * TODO:
- *  - Use P44Slot for 44.1 playback.
+ *  - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot).
  *  - 96KHz playback for DVD - use pitch of 2.0.
- *  - uLaw for Sun apps.
- *     : Alan says firmly "no software format conversion in kernel".
  *  - Retain DMA buffer on close, do not wait the end of frame.
- *  - Cleanup
- *      ? underused structure members
- *      - Remove remaining P3 tags (debug messages).
  *  - Resolve XXX tagged questions.
  *  - Cannot play 5133Hz.
  *  - 2001/01/07 Consider if we can remove voice_lock, like so:
@@ -66,14 +61,28 @@
 #endif
 #include "ymfpci.h"
 
-static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd);
+/*
+ * I do not believe in debug levels as I never can guess what
+ * part of the code is going to be problematic in the future.
+ * Don't forget to run your klogd with -c 8.
+ */
+/* #define YMFDBG(fmt, arg...)  do{ printk(KERN_DEBUG fmt, ##arg); }while(0) */
+#define YMFDBGW(fmt, arg...)  /* */
+#define YMFDBGI(fmt, arg...)  /* */
+
+static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
 static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice);
+static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice);
 static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank);
 static int ymf_playback_prepare(struct ymf_state *state);
 static int ymf_capture_prepare(struct ymf_state *state);
 static struct ymf_state *ymf_state_alloc(ymfpci_t *unit);
 
+static void ymfpci_aclink_reset(struct pci_dev * pci);
+static void ymfpci_disable_dsp(ymfpci_t *unit);
+static void ymfpci_download_image(ymfpci_t *codec);
+static void ymf_memload(ymfpci_t *unit);
+
 static LIST_HEAD(ymf_devs);
 
 /*
@@ -237,8 +246,7 @@
 }
 
 /*
- * XXX Find if this function exists in the OSS framework.
- * XXX Make sure we do no panic when ADPCM is selected.
+ * We ever allow only a few formats, but let's be generic, for smaller surprise.
  */
 static int ymf_pcm_format_width(int format)
 {
@@ -330,7 +338,7 @@
 	spin_lock_irqsave(&state->unit->reg_lock, flags);
 	dmabuf->hwptr = dmabuf->swptr = 0;
 	dmabuf->total_bytes = 0;
-	dmabuf->count = dmabuf->error = 0;
+	dmabuf->count = 0;
 	spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 
 	/* allocate DMA buffer if not allocated yet */
@@ -579,9 +587,9 @@
 	dmabuf = &ypcm->dmabuf;
 	spin_lock(&codec->reg_lock);
 	if (ypcm->running) {
-/* P3 */ /** printk("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
-  voice->number, codec->active_bank, dmabuf->count,
-  voice->bank[0].start, voice->bank[1].start); **/
+		YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
+		   voice->number, codec->active_bank, dmabuf->count,
+		   voice->bank[0].start, voice->bank[1].start);
 		silence = (ymf_pcm_format_width(state->format.format) == 16) ?
 		    0 : 0x80;
 		/* We need actual left-hand-side redzone size here. */
@@ -810,8 +818,6 @@
 		end >>= 1;
 	if (w_16)
 		end >>= 1;
-/* P3 */ // printk("ymf_pcm_init_voice: %d: Rate %d Format 0x%08x Delta 0x%x End 0x%x\n",
-//  voice->number, rate, format, delta, end);
 	for (nbank = 0; nbank < 2; nbank++) {
 		bank = &voice->bank[nbank];
 		bank->format = format;
@@ -907,7 +913,7 @@
 
 	if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
 		/* Somebody started 32 mpg123's in parallel? */
-		/* P3 */ printk("ymfpci%d: cannot allocate voice\n",
+		printk(KERN_INFO "ymfpci%d: cannot allocate voice\n",
 		    state->unit->dev_audio);
 		return err;
 	}
@@ -1178,6 +1184,7 @@
 {
 	struct ymf_state *state = (struct ymf_state *)file->private_data;
 	struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf;
+	struct ymf_unit *unit = state->unit;
 	DECLARE_WAITQUEUE(waita, current);
 	ssize_t ret;
 	unsigned long flags;
@@ -1190,18 +1197,26 @@
 		return -ENXIO;
 	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
 	ret = 0;
 
 	add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
+		spin_lock_irqsave(&unit->reg_lock, flags);
+		if (unit->suspended) {
+			spin_unlock_irqrestore(&unit->reg_lock, flags);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret) ret = -EAGAIN;
+				break;
+			}
+			continue;
+		}
 		swptr = dmabuf->swptr;
 		cnt = dmabuf->dmasize - swptr;
 		if (dmabuf->count < cnt)
 			cnt = dmabuf->count;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		spin_unlock_irqrestore(&unit->reg_lock, flags);
 
 		if (cnt > count)
 			cnt = count;
@@ -1240,7 +1255,7 @@
 			}
 			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 			if (signal_pending(current)) {
-				ret = ret ? ret : -ERESTARTSYS;
+				if (!ret) ret = -ERESTARTSYS;
 				break;
 			}
 			continue;
@@ -1253,19 +1268,24 @@
 
 		swptr = (swptr + cnt) % dmabuf->dmasize;
 
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
+		spin_lock_irqsave(&unit->reg_lock, flags);
+		if (unit->suspended) {
+			spin_unlock_irqrestore(&unit->reg_lock, flags);
+			continue;
+		}
+
 		dmabuf->swptr = swptr;
 		dmabuf->count -= cnt;
-		// spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		// spin_unlock_irqrestore(&unit->reg_lock, flags);
 
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		// spin_lock_irqsave(&state->unit->reg_lock, flags);
+		// spin_lock_irqsave(&unit->reg_lock, flags);
 		if (!state->rpcm.running) {
-			ymf_capture_trigger(state->unit, &state->rpcm, 1);
+			ymf_capture_trigger(unit, &state->rpcm, 1);
 		}
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		spin_unlock_irqrestore(&unit->reg_lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dmabuf->wait, &waita);
@@ -1278,6 +1298,7 @@
 {
 	struct ymf_state *state = (struct ymf_state *)file->private_data;
 	struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
+	struct ymf_unit *unit = state->unit;
 	DECLARE_WAITQUEUE(waita, current);
 	ssize_t ret;
 	unsigned long flags;
@@ -1286,7 +1307,7 @@
 	int redzone;
 	int delay;
 
-/* P3 */ /* printk("ymf_write: count %d\n", count); */
+	YMFDBGW("ymf_write: count %d\n", count);
 
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -1294,8 +1315,6 @@
 		return -ENXIO;
 	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
 	ret = 0;
 
 	/*
@@ -1310,7 +1329,17 @@
 
 	add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
+		spin_lock_irqsave(&unit->reg_lock, flags);
+		if (unit->suspended) {
+			spin_unlock_irqrestore(&unit->reg_lock, flags);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret) ret = -EAGAIN;
+				break;
+			}
+			continue;
+		}
 		if (dmabuf->count < 0) {
 			printk(KERN_ERR
 			   "ymf_write: count %d, was legal in cs46xx\n",
@@ -1342,22 +1371,22 @@
 		cnt = dmabuf->dmasize - swptr;
 		if (dmabuf->count + cnt > dmabuf->dmasize - redzone)
 			cnt = (dmabuf->dmasize - redzone) - dmabuf->count;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		spin_unlock_irqrestore(&unit->reg_lock, flags);
 
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-/* P3 */ /* printk("ymf_write: full, count %d swptr %d\n",
-  dmabuf->count, dmabuf->swptr); */
+			YMFDBGW("ymf_write: full, count %d swptr %d\n",
+			   dmabuf->count, dmabuf->swptr);
 			/*
 			 * buffer is full, start the dma machine and
 			 * wait for data to be played
 			 */
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
+			spin_lock_irqsave(&unit->reg_lock, flags);
 			if (!state->wpcm.running) {
-				ymf_playback_trigger(state->unit, &state->wpcm, 1);
+				ymf_playback_trigger(unit, &state->wpcm, 1);
 			}
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+			spin_unlock_irqrestore(&unit->reg_lock, flags);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				break;
@@ -1379,7 +1408,11 @@
 			swptr -= dmabuf->dmasize;
 		}
 
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
+		spin_lock_irqsave(&unit->reg_lock, flags);
+		if (unit->suspended) {
+			spin_unlock_irqrestore(&unit->reg_lock, flags);
+			continue;
+		}
 		dmabuf->swptr = swptr;
 		dmabuf->count += cnt;
 
@@ -1393,10 +1426,10 @@
 		delay = state->format.rate / 20;	/* 50ms */
 		delay <<= state->format.shift;
 		if (dmabuf->count >= delay && !state->wpcm.running) {
-			ymf_playback_trigger(state->unit, &state->wpcm, 1);
+			ymf_playback_trigger(unit, &state->wpcm, 1);
 		}
 
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		spin_unlock_irqrestore(&unit->reg_lock, flags);
 
 		count -= cnt;
 		buffer += cnt;
@@ -1406,7 +1439,7 @@
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dmabuf->wait, &waita);
 
-/* P3 */ /* printk("ymf_write: dmabuf.count %d\n", dmabuf->count); */
+	YMFDBGW("ymf_write: dmabuf.count %d\n", dmabuf->count);
 	return ret;
 }
 
@@ -1621,7 +1654,6 @@
 	case SNDCTL_DSP_CHANNELS:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_CHANNELS 0x%x\n", val); */
 		if (val != 0) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1667,19 +1699,6 @@
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 		return 0;
 
-#if 0 /* XXX Was dummy implementation anyways. Make sense of this. */
-	case SNDCTL_DSP_SUBDIVIDE:
-		dmabuf = &state->wpcm.dmabuf;
-		if (dmabuf->subdivision)
-			return -EINVAL;
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (val != 1 && val != 2)
-			return -EINVAL;
-		dmabuf->subdivision = val;
-		return 0;
-#endif
-
 	case SNDCTL_DSP_SETFRAGMENT:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
@@ -1729,40 +1748,6 @@
 			    (int *)arg); */
 		return put_user(0, (int *)arg);
 
-#if 0 /* not implememnted, yet? */
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		dmabuf = &state->wpcm.dmabuf;
-		if (file->f_mode & FMODE_READ && dmabuf->enable)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && dmabuf->enable)
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, (int *)arg);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			dmabuf = &state->rpcm.dmabuf;
-			if (val & PCM_ENABLE_INPUT) {
-				if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-					return ret;
-				start_adc(state);
-			} else
-				stop_adc(state);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			dmabuf = &state->wpcm.dmabuf;
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-					return ret;
-				start_dac(state);  // sure?
-			} else
-				stop_dac(state);
-		}
-		return 0;
-#endif
-
 	case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
@@ -1794,18 +1779,6 @@
 	case SNDCTL_DSP_SETDUPLEX:	/* XXX TODO */
 		return -EINVAL;
 
-#if 0 /* XXX implement when an app found that uses it. */
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
-		cs_update_ptr(state);
-		dmabuf = &state->wpcm.dmabuf;
-		val = dmabuf->count;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		return put_user(val, (int *)arg);
-#endif
-
 	case SOUND_PCM_READ_RATE:
 		return put_user(state->format.rate, (int *)arg);
 
@@ -1827,7 +1800,6 @@
 		 * Some programs mix up audio devices and ioctls
 		 * or perhaps they expect "universal" ioctls,
 		 * for instance we get SNDCTL_TMR_CONTINUE here.
-		 * XXX Is there sound_generic_ioctl() around?
 		 */
 		 break;
 	}
@@ -2017,6 +1989,79 @@
 };
 
 /*
+ */
+
+static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
+{
+	struct ymf_unit *unit = pci_get_drvdata(pcidev);
+	unsigned long flags;
+	struct ymf_dmabuf *dmabuf;
+	struct list_head *p;
+	struct ymf_state *state;
+
+	spin_lock_irqsave(&unit->reg_lock, flags);
+
+	unit->suspended = 1;
+
+	list_for_each(p, &unit->states) {
+		state = list_entry(p, struct ymf_state, chain);
+
+		dmabuf = &state->wpcm.dmabuf;
+		dmabuf->hwptr = dmabuf->swptr = 0;
+		dmabuf->total_bytes = 0;
+		dmabuf->count = 0;
+
+		dmabuf = &state->rpcm.dmabuf;
+		dmabuf->hwptr = dmabuf->swptr = 0;
+		dmabuf->total_bytes = 0;
+		dmabuf->count = 0;
+	}
+
+	ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0);
+	ymfpci_disable_dsp(unit);
+
+	spin_unlock_irqrestore(&unit->reg_lock, flags);
+	
+	return 0;
+}
+
+static int ymf_resume(struct pci_dev *pcidev)
+{
+	struct ymf_unit *unit = pci_get_drvdata(pcidev);
+	unsigned long flags;
+	struct list_head *p;
+	struct ymf_state *state;
+
+	ymfpci_aclink_reset(unit->pci);
+	ymfpci_codec_ready(unit, 0, 1);		/* prints diag if not ready. */
+
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+	/* XXX At this time the legacy registers are probably deprogrammed. */
+#endif
+
+	ymfpci_download_image(unit);
+
+	ymf_memload(unit);
+
+	spin_lock_irqsave(&unit->reg_lock, flags);
+
+	if (unit->start_count) {
+		ymfpci_writel(unit, YDSXGR_MODE, 3);
+		unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
+	}
+
+	unit->suspended = 0;
+	list_for_each(p, &unit->states) {
+		state = list_entry(p, struct ymf_state, chain);
+		wake_up(&state->wpcm.dmabuf.wait);
+		wake_up(&state->rpcm.dmabuf.wait);
+	}
+
+	spin_unlock_irqrestore(&unit->reg_lock, flags);
+	return 0;
+}
+
+/*
  *  initialization routines
  */
 
@@ -2176,6 +2221,9 @@
 	}
 
 	ymfpci_enable_dsp(codec);
+
+	/* 0.02s sounds not too bad, we may do schedule_timeout() later. */
+	mdelay(20); /* seems we need some delay after downloading image.. */
 }
 
 static int ymfpci_memalloc(ymfpci_t *codec)
@@ -2239,28 +2287,6 @@
 	ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff;
 	codec->work_base = ptr;
 
-	ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, virt_to_bus(codec->bank_base_playback));
-	ymfpci_writel(codec, YDSXGR_RECCTRLBASE, virt_to_bus(codec->bank_base_capture));
-	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, virt_to_bus(codec->bank_base_effect));
-	ymfpci_writel(codec, YDSXGR_WORKBASE, virt_to_bus(codec->work_base));
-	ymfpci_writel(codec, YDSXGR_WORKSIZE, codec->work_size >> 2);
-
-	/* S/PDIF output initialization */
-	ymfpci_writew(codec, YDSXGR_SPDIFOUTCTRL, 0);
-	ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,
-		SND_PCM_AES0_CON_EMPHASIS_NONE |
-		(SND_PCM_AES1_CON_ORIGINAL << 8) |
-		(SND_PCM_AES1_CON_PCM_CODER << 8));
-
-	/* S/PDIF input initialization */
-	ymfpci_writew(codec, YDSXGR_SPDIFINCTRL, 0);
-
-	/* move this volume setup to mixer */
-	ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
-	ymfpci_writel(codec, YDSXGR_BUF441OUTVOL, 0);
-	ymfpci_writel(codec, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
-	ymfpci_writel(codec, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
-
 	return 0;
 }
 
@@ -2274,6 +2300,32 @@
 	kfree(codec->work_ptr);
 }
 
+static void ymf_memload(ymfpci_t *unit)
+{
+
+	ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, virt_to_bus(unit->bank_base_playback));
+	ymfpci_writel(unit, YDSXGR_RECCTRLBASE, virt_to_bus(unit->bank_base_capture));
+	ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, virt_to_bus(unit->bank_base_effect));
+	ymfpci_writel(unit, YDSXGR_WORKBASE, virt_to_bus(unit->work_base));
+	ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
+
+	/* S/PDIF output initialization */
+	ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0);
+	ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS,
+		SND_PCM_AES0_CON_EMPHASIS_NONE |
+		(SND_PCM_AES1_CON_ORIGINAL << 8) |
+		(SND_PCM_AES1_CON_PCM_CODER << 8));
+
+	/* S/PDIF input initialization */
+	ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0);
+
+	/* move this volume setup to mixer */
+	ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
+	ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0);
+	ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
+	ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
+}
+
 static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
 {
 	struct ac97_codec *codec;
@@ -2380,12 +2432,9 @@
 
 	ymfpci_download_image(codec);
 
-	udelay(100); /* seems we need some delay after downloading image.. */
-
 	if (ymfpci_memalloc(codec) < 0)
 		goto out_disable_dsp;
-
-	/* ymfpci_proc_init(unit, codec); */
+	ymf_memload(codec);
 
 	if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) {
 		printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
@@ -2481,6 +2530,8 @@
 	id_table:	ymf_id_tbl,
 	probe:		ymf_probe_one,
 	remove:         ymf_remove_one,
+	suspend:	ymf_suspend,
+	resume:		ymf_resume
 };
 
 static int __init ymf_init_module(void)
diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ymfpci.h linux/drivers/sound/ymfpci.h
--- v2.4.6/linux/drivers/sound/ymfpci.h	Tue May 15 11:16:26 2001
+++ linux/drivers/sound/ymfpci.h	Wed Jul  4 11:50:39 2001
@@ -257,6 +257,7 @@
 	ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
 
 	int start_count;
+	int suspended;
 
 	u32 active_bank;
 	struct ymf_voice voices[64];
@@ -282,8 +283,6 @@
 
 	struct list_head ymf_devs;
 	struct list_head states;	/* List of states for this unit */
-	/* For the moment we do not traverse list of states so it is
-	 * entirely useless. Will be used (PM) or killed. XXX */
 };
 
 struct ymf_dmabuf {
@@ -300,7 +299,6 @@
 	int count;		/* fill count */
 	unsigned total_bytes;	/* total bytes dmaed by hardware */
 
-	unsigned error;		/* number of over/underruns */
 	wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
 
 	/* redundant, but makes calculations easier */
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.4.6/linux/drivers/usb/acm.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/acm.c	Wed Jul  4 20:11:17 2001
@@ -1,5 +1,5 @@
 /*
- * acm.c  Version 0.18
+ * acm.c  Version 0.19
  *
  * Copyright (c) 1999 Armin Fuerst	<fuerst@in.tum.de>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
@@ -21,6 +21,7 @@
  *	v0.16 - added code for modems with swapped data and control interfaces
  *	v0.17 - added new style probing
  *	v0.18 - fixed new style probing for devices with more configurations
+ *	v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
  */
 
 /*
@@ -51,6 +52,7 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <linux/smp_lock.h>
 #undef DEBUG
 #include <linux/usb.h>
 
@@ -202,13 +204,10 @@
 
 			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;
 
@@ -305,7 +304,14 @@
 
 	MOD_INC_USE_COUNT;
 
-	if (acm->used++) return 0;
+        lock_kernel();
+
+	if (acm->used++) {
+                unlock_kernel();
+                return 0;
+        }
+
+        unlock_kernel();
 
 	acm->ctrlurb.dev = acm->dev;
 	if (usb_submit_urb(&acm->ctrlurb))
@@ -410,7 +416,7 @@
 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;
+	unsigned int mask, newctrl;
 
 	if (!ACM_READY(acm)) return -EINVAL;
 
@@ -429,7 +435,8 @@
 		case TIOCMBIS:
 		case TIOCMBIC:
 
-			if ((retval = get_user(mask, (unsigned long *) arg))) return retval;
+			if (get_user(mask, (unsigned long *) arg))
+				return -EFAULT;
 
 			newctrl = acm->ctrlout;
 			mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
@@ -475,7 +482,7 @@
 		(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;
+	acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
 
 	if (!newline.speed) {
 		newline.speed = acm->line.speed;
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
--- v2.4.6/linux/drivers/usb/devices.c	Mon Sep 25 15:25:29 2000
+++ linux/drivers/usb/devices.c	Wed Jul  4 20:11:17 2001
@@ -475,6 +475,7 @@
 		return -EFAULT;
 
 	/* enumerate busses */
+	read_lock_irq (&usb_bus_list_lock);
 	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);
@@ -484,6 +485,7 @@
 			return ret;
 		total_written += ret;
 	}
+	read_unlock_irq (&usb_bus_list_lock);
 	return total_written;
 }
 
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.4.6/linux/drivers/usb/inode.c	Tue May 22 10:25:36 2001
+++ linux/drivers/usb/inode.c	Wed Jul  4 20:11:17 2001
@@ -260,11 +260,15 @@
         struct list_head *list;
         struct usb_bus *bus;
 
+	read_lock_irq (&usb_bus_list_lock);
         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)
+                if (bus->busnum == busnr) {
+			read_unlock_irq (&usb_bus_list_lock);
                         return bus;
+		}
         }
+	read_unlock_irq (&usb_bus_list_lock);
         return NULL;
 }
 
@@ -412,7 +416,7 @@
 		if (i < 2+NRSPECIAL)
 			return 0;
 		i -= 2+NRSPECIAL;
-		lock_kernel();
+		read_lock_irq (&usb_bus_list_lock);
 		for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
 			if (i > 0) {
 				i--;
@@ -424,7 +428,7 @@
 				break;
 			filp->f_pos++;
 		}
-		unlock_kernel();
+		read_unlock_irq (&usb_bus_list_lock);
 		return 0;
 	}
 }
@@ -635,13 +639,13 @@
 		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();
+	read_lock_irq (&usb_bus_list_lock);
 	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();
+	read_unlock_irq (&usb_bus_list_lock);
         return s;
 
  out_no_root:
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- v2.4.6/linux/drivers/usb/mdc800.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/mdc800.c	Wed Jul  4 15:39:28 2001
@@ -716,6 +716,7 @@
 static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
 {
 	int i=0;
+	char c;
 
 	spin_lock (&mdc800->io_lock);
 	if (mdc800->state != READY)
@@ -738,7 +739,14 @@
 		}
 
 		/* check for command start */
-		if (buf [i] == (char) 0x55)
+		
+		if(get_user(c, buf+i))
+		{
+			spin_unlock (&mdc800->io_lock);
+			return -EFAULT;
+		}
+		
+		if (c == (char) 0x55)
 		{
 			mdc800->in_count=0;
 			mdc800->out_count=0;
@@ -749,7 +757,7 @@
 		/* save command byte */
 		if (mdc800->in_count < 8)
 		{
-			mdc800->in[mdc800->in_count]=buf[i];
+			mdc800->in[mdc800->in_count]=c;
 			mdc800->in_count++;
 		}
 		else
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.4.6/linux/drivers/usb/printer.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/printer.c	Fri Jul  6 17:04:29 2001
@@ -19,6 +19,7 @@
  *	v0.6 - never time out
  *	v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
  *	v0.8 - add devfs support
+ *	v0.9 - fix unplug-while-open paths
  */
 
 /*
@@ -88,6 +89,7 @@
 struct usblp {
 	struct usb_device 	*dev;			/* USB device */
 	devfs_handle_t		devfs;			/* devfs device */
+	struct semaphore	sem;			/* locks this struct, especially "dev" */
 	struct urb		readurb, writeurb;	/* The urbs */
 	wait_queue_head_t	wait;			/* Zzzzz ... */
 	int			readcount;		/* Counter for reads */
@@ -172,9 +174,12 @@
 static int usblp_check_status(struct usblp *usblp, int err)
 {
 	unsigned char status, newerr = 0;
+	int error;
 
-	if (usblp_read_status(usblp, &status)) {
-		err("usblp%d: failed reading printer status", usblp->minor);
+	error = usblp_read_status (usblp, &status);
+	if (error < 0) {
+		err("usblp%d: error %d reading printer status",
+			usblp->minor, error);
 		return 0;
 	}
 
@@ -244,24 +249,30 @@
 	return retval;
 }
 
+static void usblp_cleanup (struct usblp *usblp)
+{
+	devfs_unregister (usblp->devfs);
+	usblp_table [usblp->minor] = NULL;
+	info ("usblp%d: removed", usblp->minor);
+
+	kfree (usblp->writeurb.transfer_buffer);
+	kfree (usblp->device_id_string);
+	kfree (usblp);
+}
+
 static int usblp_release(struct inode *inode, struct file *file)
 {
 	struct usblp *usblp = file->private_data;
 
+	down (&usblp->sem);
 	usblp->used = 0;
-
 	if (usblp->dev) {
 		if (usblp->bidir)
 			usb_unlink_urb(&usblp->readurb);
 		usb_unlink_urb(&usblp->writeurb);
-		return 0;
-	}
-
-	devfs_unregister(usblp->devfs);
-	usblp_table[usblp->minor] = NULL;
-	kfree(usblp->device_id_string);
-	kfree(usblp);
-
+		up(&usblp->sem);
+	} else 		/* finish cleanup from disconnect */
+		usblp_cleanup (usblp);
 	return 0;
 }
 
@@ -279,21 +290,31 @@
 	struct usblp *usblp = file->private_data;
 	int length, err;
 	unsigned char status;
+	int retval = 0;
+
+	down (&usblp->sem);
+	if (!usblp->dev) {
+		retval = -ENODEV;
+		goto done;
+	}
 
 	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
 	
 		switch (_IOC_NR(cmd)) {
 
 			case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
-				if (_IOC_DIR(cmd) != _IOC_READ)
-					return -EINVAL;
+				if (_IOC_DIR(cmd) != _IOC_READ) {
+					retval = -EINVAL;
+					goto done;
+				}
 
 				err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
 				if (err < 0) {
 					dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
 						usblp->minor, err);
 					usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
-					return -EIO;
+					retval = -EIO;
+					goto done;
 				}
 
 				length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
@@ -307,13 +328,16 @@
 
 				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;
+				if (copy_to_user((unsigned char *) arg,
+						usblp->device_id_string, (unsigned long) length)) {
+					retval = -EFAULT;
+					goto done;
+				}
 
 				break;
 
 			default:
-				return -EINVAL;
+				retval = -EINVAL;
 		}
 	else	/* old-style ioctl value */
 		switch (cmd) {
@@ -321,17 +345,20 @@
 			case LPGETSTATUS:
 				if (usblp_read_status(usblp, &status)) {
 					err("usblp%d: failed reading printer status", usblp->minor);
-					return -EIO;
+					retval = -EIO;
+					goto done;
 				}
 				if (copy_to_user ((unsigned char *)arg, &status, 1))
-					return -EFAULT;
+					retval = -EFAULT;
 				break;
 
 			default:
-				return -EINVAL;
+				retval = -EINVAL;
 		}
 
-	return 0;
+done:
+	up (&usblp->sem);
+	return retval;
 }
 
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
@@ -341,6 +368,8 @@
 
 	while (writecount < count) {
 
+		// FIXME:  only use urb->status inside completion
+		// callbacks; this way is racey...
 		if (usblp->writeurb.status == -EINPROGRESS) {
 
 			if (file->f_flags & O_NONBLOCK)
@@ -356,28 +385,36 @@
 			}
 		}
 
-		if (!usblp->dev)
+		down (&usblp->sem);
+		if (!usblp->dev) {
+			up (&usblp->sem);
 			return -ENODEV;
+		}
 
-		if (usblp->writeurb.status) {
+		if (usblp->writeurb.status != 0) {
 			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
 				if (usblp->writeurb.status != -EINPROGRESS)
 					err("usblp%d: error %d writing to printer",
 						usblp->minor, usblp->writeurb.status);
 				err = usblp->writeurb.status;
-				continue;
-			}
-			else {
+			} else
 				err = usblp_check_status(usblp, err);
-				continue;
-			}
+			up (&usblp->sem);
+
+			/* if the fault was due to disconnect, let khubd's
+			 * call to usblp_disconnect() grab usblp->sem ...
+			 */
+			schedule ();
+			continue;
 		}
 
 		writecount += usblp->writeurb.transfer_buffer_length;
 		usblp->writeurb.transfer_buffer_length = 0;
 
-		if (writecount == count)
-			continue;
+		if (writecount == count) {
+			up (&usblp->sem);
+			break;
+		}
 
 		usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
 							 (count - writecount) : USBLP_BUF_SIZE;
@@ -387,6 +424,7 @@
 
 		usblp->writeurb.dev = usblp->dev;
 		usb_submit_urb(&usblp->writeurb);
+		up (&usblp->sem);
 	}
 
 	return count;
@@ -399,20 +437,36 @@
 	if (!usblp->bidir)
 		return -EINVAL;
 
+	down (&usblp->sem);
+	if (!usblp->dev) {
+		count = -ENODEV;
+		goto done;
+	}
+
 	if (usblp->readurb.status == -EINPROGRESS) {
 
-		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
+		if (file->f_flags & O_NONBLOCK) {
+			count = -EAGAIN;
+			goto done;
+		}
 
+		// FIXME:  only use urb->status inside completion
+		// callbacks; this way is racey...
 		while (usblp->readurb.status == -EINPROGRESS) {
-			if (signal_pending(current))
-				return -EINTR;
+			if (signal_pending(current)) {
+				count = -EINTR;
+				goto done;
+			}
+			up (&usblp->sem);
 			interruptible_sleep_on(&usblp->wait);
+			down (&usblp->sem);
 		}
 	}
 
-	if (!usblp->dev)
-		return -ENODEV;
+	if (!usblp->dev) {
+		count = -ENODEV;
+		goto done;
+	}
 
 	if (usblp->readurb.status) {
 		err("usblp%d: error %d reading from printer",
@@ -420,14 +474,17 @@
 		usblp->readurb.dev = usblp->dev;
  		usblp->readcount = 0;
 		usb_submit_urb(&usblp->readurb);
-		return -EIO;
+		count = -EIO;
+		goto done;
 	}
 
 	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 (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) {
+		count = -EFAULT;
+		goto done;
+	}
 
 	if ((usblp->readcount += count) == usblp->readurb.actual_length) {
 		usblp->readcount = 0;
@@ -435,6 +492,8 @@
 		usb_submit_urb(&usblp->readurb);
 	}
 
+done:
+	up (&usblp->sem);
 	return count;
 }
 
@@ -537,6 +596,7 @@
 		return NULL;
 	}
 	memset(usblp, 0, sizeof(struct usblp));
+	init_MUTEX (&usblp->sem);
 
 	/* lookup quirks for this printer */
 	quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);
@@ -599,14 +659,12 @@
 
 	sprintf(name, "lp%d", minor);
 	
-	/* Create with perms=664 */
+	/* if we have devfs, create with perms=660 */
 	usblp->devfs = devfs_register(usb_devfs_handle, name,
 				      DEVFS_FL_DEFAULT, USB_MAJOR,
 				      USBLP_MINOR_BASE + minor,
 				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
 				      S_IWGRP, &usblp_fops, NULL);
-	if (usblp->devfs == NULL)
-		err("usblp%d: device node registration failed", minor);
 
 	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
 		minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
@@ -619,25 +677,21 @@
 	struct usblp *usblp = ptr;
 
 	if (!usblp || !usblp->dev) {
-		err("disconnect on nonexisting interface");
-		return;
+		err("bogus disconnect");
+		BUG ();
 	}
 
+	down (&usblp->sem);
 	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);
-
-	devfs_unregister(usblp->devfs);
-	usblp_table[usblp->minor] = NULL;
-	kfree(usblp);
+	if (!usblp->used)
+		usblp_cleanup (usblp);
+	else 	/* cleanup later, on close */
+		up (&usblp->sem);
 }
 
 static struct usb_device_id usblp_ids [] = {
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.4.6/linux/drivers/usb/scanner.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/usb/scanner.c	Sun Jul  8 13:17:30 2001
@@ -909,7 +909,7 @@
 		return result;
 	}
 	default:
-		return -ENOIOCTLCMD;
+		return -ENOTTY;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- v2.4.6/linux/drivers/usb/serial/empeg.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/empeg.c	Fri Jul  6 17:04:29 2001
@@ -247,7 +247,6 @@
 static void empeg_close (struct usb_serial_port *port, struct file * filp)
 {
 	struct usb_serial *serial;
-	unsigned char *transfer_buffer;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
@@ -263,14 +262,6 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-
-		if (!transfer_buffer) {
-			err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
-		} else {
-			kfree (transfer_buffer);
-		}
-
 		/* shutdown our bulk read */
 		usb_unlink_urb (port->read_urb);
 		port->active = 0;
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.4.6/linux/drivers/usb/serial/ftdi_sio.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Fri Jul  6 17:04:29 2001
@@ -902,7 +902,8 @@
 
 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
 		dbg(__FUNCTION__ " TIOCMSET");
-		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+		if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
 		urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
 		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
 			err("Error from DTR set urb (TIOCMSET)");
@@ -915,7 +916,8 @@
 					
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
 		dbg(__FUNCTION__ " TIOCMBIS");
- 	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ 	        if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
   	        if (mask & TIOCM_DTR){
 			if ((ret = set_dtr(serial->dev, 
 					   usb_sndctrlpipe(serial->dev, 0),
@@ -936,7 +938,8 @@
 
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
 		dbg(__FUNCTION__ " TIOCMBIC");
- 	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ 	        if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
   	        if (mask & TIOCM_DTR){
 			if ((ret = set_dtr(serial->dev, 
 					   usb_sndctrlpipe(serial->dev, 0),
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.4.6/linux/drivers/usb/serial/usbserial.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/usbserial.c	Fri Jul  6 17:04:29 2001
@@ -15,6 +15,13 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (07/03/2001) gkh
+ *	Fixed module paramater size.  Thanks to John Brockmeyer for the pointer.
+ *	Fixed vendor and product getting defined through the MODULE_PARM macro
+ *	if the Generic driver wasn't compiled in.
+ *	Fixed problem with generic_shutdown() not being called for drivers that
+ *	don't have a shutdown() function.
+ *
  * (06/06/2001) gkh
  *	added evil hack that is needed for the prolific pl2303 device due to the
  *	crazy way its endpoints are set up.
@@ -296,7 +303,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2"
+#define DRIVER_VERSION "v1.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"
 #define DRIVER_DESC "USB Serial Driver core"
 
@@ -347,6 +354,7 @@
 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 serial_shutdown (struct usb_serial *serial);
 
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
 			       const struct usb_device_id *id);
@@ -736,6 +744,16 @@
 }
 
 
+static void serial_shutdown (struct usb_serial *serial)
+{
+	if (serial->type->shutdown) {
+		serial->type->shutdown(serial);
+	} else {
+		generic_shutdown(serial);
+	}
+}
+
+
 
 /*****************************************************************************
  * generic devices specific driver functions
@@ -1311,8 +1329,7 @@
 				serial->port[i].tty->driver_data = NULL;
 		}
 
-		if (serial->type->shutdown)
-			serial->type->shutdown(serial);
+		serial_shutdown (serial);
 
 		for (i = 0; i < serial->num_ports; ++i)
 			serial->port[i].active = 0;
@@ -1426,7 +1443,7 @@
 		return -1;
 	}
 
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_DESC " " DRIVER_VERSION);
 
 	return 0;
 }
@@ -1500,9 +1517,11 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-MODULE_PARM(vendor, "i");
+#ifdef CONFIG_USB_SERIAL_GENERIC
+MODULE_PARM(vendor, "h");
 MODULE_PARM_DESC(vendor, "User specified USB idVendor");
 
-MODULE_PARM(product, "i");
+MODULE_PARM(product, "h");
 MODULE_PARM_DESC(product, "User specified USB idProduct");
+#endif
 
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c
--- v2.4.6/linux/drivers/usb/storage/freecom.c	Tue Nov 28 21:50:07 2000
+++ linux/drivers/usb/storage/freecom.c	Wed Jul  4 15:43:05 2001
@@ -96,7 +96,7 @@
 #define FCM_PACKET_OUTPUT 0x01
 
 /* Write a value to an ide register.  Or the ide register to write after
- * munging the addres a bit. */
+ * munging the address a bit. */
 #define FCM_PACKET_IDE_WRITE    0x40
 #define FCM_PACKET_IDE_READ     0xC0
 
@@ -412,7 +412,7 @@
 
         US_DEBUG(pdump ((void *) fst, partial));
 
-	/* while we haven't recieved the IRQ */
+	/* while we haven't received the IRQ */
 	while (!(fst->Status & 0x2)) {
 		/* send a command to re-fetch the status */
 		US_DEBUGP("Re-attempting to get status...\n");
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.6/linux/drivers/usb/uhci.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/uhci.c	Wed Jul  4 15:43:05 2001
@@ -62,7 +62,7 @@
  * Version Information
  */
 #define DRIVER_VERSION ""
-#define DRIVER_AUTHOR "Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
+#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
 
@@ -305,8 +305,7 @@
 	mb();
 	td->link = UHCI_PTR_TERM;
 
-	list_del(&td->fl_list);
-	INIT_LIST_HEAD(&td->fl_list);
+	list_del_init(&td->fl_list);
 	td->frame = -1;
 
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
@@ -438,8 +437,7 @@
 	mb();
 	qh->element = qh->link = UHCI_PTR_TERM;
 
-	list_del(&qh->list);
-	INIT_LIST_HEAD(&qh->list);
+	list_del_init(&qh->list);
 
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 
@@ -624,8 +622,7 @@
 			pltd->link = UHCI_PTR_TERM;
 	}
 
-	list_del(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->queue_list);
+	list_del_init(&urbp->queue_list);
 
 out:
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
@@ -689,8 +686,7 @@
 	if (list_empty(&td->list))
 		return;
 
-	list_del(&td->list);
-	INIT_LIST_HEAD(&td->list);
+	list_del_init(&td->list);
 
 	td->urb = NULL;
 }
@@ -1665,8 +1661,7 @@
 			usb_pipetype(urb->pipe), urb);
 	}
 
-	list_del(&urb->urb_list);
-	INIT_LIST_HEAD(&urb->urb_list);
+	list_del_init(&urb->urb_list);
 
 	uhci_add_complete(urb);
 }
@@ -1723,8 +1718,7 @@
 		return 0;
 
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	list_del(&urb->urb_list);
-	INIT_LIST_HEAD(&urb->urb_list);
+	list_del_init(&urb->urb_list);
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
 	uhci_unlink_generic(uhci, urb);
@@ -2206,8 +2200,7 @@
 
 		tmp = tmp->next;
 
-		list_del(&qh->remove_list);
-		INIT_LIST_HEAD(&qh->remove_list);
+		list_del_init(&qh->remove_list);
 
 		uhci_free_qh(uhci, qh);
 	}
@@ -2300,8 +2293,7 @@
 
 		tmp = tmp->next;
 
-		list_del(&urbp->complete_list);
-		INIT_LIST_HEAD(&urbp->complete_list);
+		list_del_init(&urbp->complete_list);
 
 		uhci_call_completion(urb);
 	}
@@ -2322,8 +2314,7 @@
 
 		tmp = tmp->next;
 
-		list_del(&urb->urb_list);
-		INIT_LIST_HEAD(&urb->urb_list);
+		list_del_init(&urb->urb_list);
 
 		urbp->status = urb->status = -ECONNRESET;
 		uhci_call_completion(urb);
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.4.6/linux/drivers/usb/usb-ohci.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/usb-ohci.c	Sun Jul  8 13:17:30 2001
@@ -2749,7 +2749,7 @@
 
 		switch (when) {
 		case PBOOK_SLEEP_NOW:
-			ohci_pci_suspend (ohci->ohci_dev);
+			ohci_pci_suspend (ohci->ohci_dev, 3);
 			break;
 		case PBOOK_WAKE:
 			ohci_pci_resume (ohci->ohci_dev);
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/usb-skeleton.c linux/drivers/usb/usb-skeleton.c
--- v2.4.6/linux/drivers/usb/usb-skeleton.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb-skeleton.c	Wed Jul  4 15:43:05 2001
@@ -0,0 +1,652 @@
+/*
+ * USB Skeleton driver
+ *
+ * Copyright (c) 2001 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.
+ *
+ *
+ * This driver is to be used as a skeleton driver to be able to create a
+ * USB driver quickly.  The design of it is based on the usb-serial and
+ * dc2xx drivers.
+ *
+ * Thanks to Oliver Neukum and David Brownell for their help in debugging
+ * this driver.
+ *
+ * TODO:
+ *	- fix urb->status race condition in write sequence
+ *	- move minor_table to a dynamic list.
+ *
+ * History:
+ *
+ * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
+ * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people
+ * 2001_05_01 - 0.1 - first version
+ * 
+ */
+
+#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/slab.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.3"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
+#define DRIVER_DESC "USB Skeleton Driver"
+
+/* Module paramaters */
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+
+/* Define these values to match your device */
+#define USB_SKEL_VENDOR_ID	0xfff0
+#define USB_SKEL_PRODUCT_ID	0xfff0
+
+/* table of devices that work with this driver */
+static struct usb_device_id skel_table [] = {
+	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, skel_table);
+
+
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE	200	
+
+/* we can have up to this number of device plugged in at once */
+#define MAX_DEVICES		16
+
+/* Structure to hold all of our device specific stuff */
+struct usb_skel {
+	struct usb_device *	udev;			/* save off the usb device pointer */
+	struct usb_interface *	interface;		/* the interface for this device */
+	devfs_handle_t		devfs;			/* devfs device node */
+	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 */
+
+	unsigned char *		bulk_in_buffer;		/* the buffer to receive data */
+	int			bulk_in_size;		/* the size of the receive buffer */
+	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
+
+	unsigned char *		bulk_out_buffer;	/* the buffer to send data */
+	int			bulk_out_size;		/* the size of the send buffer */
+	struct urb *		write_urb;		/* the urb used to send data */
+	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
+
+	struct tq_struct	tqueue;			/* task queue for line discipline waking up */
+	int			open_count;		/* number of times this port has been opened */
+	struct semaphore	sem;			/* locks this structure */
+};
+
+
+/* the global usb devfs handle */
+extern devfs_handle_t usb_devfs_handle;
+
+
+/* local function prototypes */
+static ssize_t skel_read	(struct file *file, char *buffer, size_t count, loff_t *ppos);
+static ssize_t skel_write	(struct file *file, const char *buffer, size_t count, loff_t *ppos);
+static int skel_ioctl		(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int skel_open		(struct inode *inode, struct file *file);
+static int skel_release		(struct inode *inode, struct file *file);
+	
+static void * skel_probe	(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);
+static void skel_disconnect	(struct usb_device *dev, void *ptr);
+
+static void skel_write_bulk_callback	(struct urb *urb);
+
+
+/* array of pointers to our devices that are currently connected */
+static struct usb_skel		*minor_table[MAX_DEVICES];
+
+/* lock to protect the minor_table structure */
+static DECLARE_MUTEX (minor_table_mutex);
+
+/* file operations needed when we register this driver */
+static struct file_operations skel_fops = {
+	owner:		THIS_MODULE,
+	read:		skel_read,
+	write:		skel_write,
+	ioctl:		skel_ioctl,
+	open:		skel_open,
+	release:	skel_release,
+};      
+
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver skel_driver = {
+	name:		"skeleton",
+	probe:		skel_probe,
+	disconnect:	skel_disconnect,
+	fops:		&skel_fops,
+	minor:		USB_SKEL_MINOR_BASE,
+	id_table:	skel_table,
+};
+
+
+
+
+
+/**
+ *	usb_skel_debug_data
+ */
+static inline void usb_skel_debug_data (const char *function, int size, const unsigned char *data)
+{
+	int i;
+
+	if (!debug)
+		return;
+	
+	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", 
+		function, size);
+	for (i = 0; i < size; ++i) {
+		printk ("%.2x ", data[i]);
+	}
+	printk ("\n");
+}
+
+
+/**
+ *	skel_open
+ */
+static int skel_open (struct inode *inode, struct file *file)
+{
+	struct usb_skel *dev = NULL;
+	int subminor;
+	int retval = 0;
+	
+	dbg(__FUNCTION__);
+
+	subminor = MINOR (inode->i_rdev) - USB_SKEL_MINOR_BASE;
+	if ((subminor < 0) ||
+	    (subminor >= MAX_DEVICES)) {
+		return -ENODEV;
+	}
+
+	/* increment our usage count for the module */
+	MOD_INC_USE_COUNT;
+
+	/* lock our minor table and get our local data for this minor */
+	down (&minor_table_mutex);
+	dev = minor_table[subminor];
+	if (dev == NULL) {
+		up (&minor_table_mutex);
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	/* lock this device */
+	down (&dev->sem);
+
+	/* unlock the minor table */
+	up (&minor_table_mutex);
+
+	/* increment our usage count for the driver */
+	++dev->open_count;
+
+	/* save our object in the file's private structure */
+	file->private_data = dev;
+
+	/* unlock this device */
+	up (&dev->sem);
+
+	return retval;
+}
+
+
+/**
+ *	skel_release
+ */
+static int skel_release (struct inode *inode, struct file *file)
+{
+	struct usb_skel *dev;
+	int retval = 0;
+
+	dev = (struct usb_skel *)file->private_data;
+	if (dev == NULL) {
+		dbg (__FUNCTION__ " - object is NULL");
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - minor %d", dev->minor);
+
+	/* lock our minor table */
+	down (&minor_table_mutex);
+
+	/* lock our device */
+	down (&dev->sem);
+
+	if (dev->open_count <= 0) {
+		dbg (__FUNCTION__ " - device not opened");
+		retval = -ENODEV;
+		goto exit_not_opened;
+	}
+
+	if (dev->udev == NULL) {
+		/* the device was unplugged before the file was released */
+		minor_table[dev->minor] = NULL;
+		if (dev->bulk_in_buffer != NULL)
+			kfree (dev->bulk_in_buffer);
+		if (dev->bulk_out_buffer != NULL)
+			kfree (dev->bulk_out_buffer);
+		if (dev->write_urb != NULL)
+			usb_free_urb (dev->write_urb);
+		kfree (dev);
+		goto exit;
+	}
+
+	/* decrement our usage count for the device */
+	--dev->open_count;
+	if (dev->open_count <= 0) {
+		/* shutdown any bulk writes that might be going on */
+		dev->write_urb->transfer_flags |= USB_ASYNC_UNLINK;
+		usb_unlink_urb (dev->write_urb);
+		dev->open_count = 0;
+	}
+
+exit:
+	/* decrement our usage count for the module */
+	MOD_DEC_USE_COUNT;
+
+exit_not_opened:
+	up (&dev->sem);
+	up (&minor_table_mutex);
+
+	return retval;
+}
+
+
+/**
+ *	skel_read
+ */
+static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_skel *dev;
+	int retval = 0;
+
+	dev = (struct usb_skel *)file->private_data;
+	
+	dbg(__FUNCTION__ " - minor %d, count = %d", dev->minor, count);
+
+	/* lock this object */
+	down (&dev->sem);
+
+	/* verify that the device wasn't unplugged */
+	if (dev->udev == NULL) {
+		up (&dev->sem);
+		return -ENODEV;
+	}
+	
+	/* do an immediate bulk read to get data from the device */
+	retval = usb_bulk_msg (dev->udev,
+			       usb_rcvbulkpipe (dev->udev, 
+						dev->bulk_in_endpointAddr),
+			       dev->bulk_in_buffer, dev->bulk_in_size,
+			       &count, HZ*10);
+
+	/* if the read was successful, copy the data to userspace */
+	if (!retval) {
+		if (copy_to_user (buffer, dev->bulk_in_buffer, count))
+			retval = -EFAULT;
+		else
+			retval = count;
+	}
+	
+	/* unlock the device */
+	up (&dev->sem);
+	return retval;
+}
+
+
+/**
+ *	skel_write
+ */
+static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_skel *dev;
+	ssize_t bytes_written = 0;
+	int retval = 0;
+
+	dev = (struct usb_skel *)file->private_data;
+
+	dbg(__FUNCTION__ " - minor %d, count = %d", dev->minor, count);
+
+	/* lock this object */
+	down (&dev->sem);
+
+	/* verify that the device wasn't unplugged */
+	if (dev->udev == NULL) {
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	/* verify that we actually have some data to write */
+	if (count == 0) {
+		dbg(__FUNCTION__ " - write request of 0 bytes");
+		goto exit;
+	}
+
+	/* see if we are already in the middle of a write */
+	if (dev->write_urb->status == -EINPROGRESS) {
+		dbg (__FUNCTION__ " - already writing");
+		goto exit;
+	}
+
+	/* we can only write as much as 1 urb will hold */
+	bytes_written = (count > dev->bulk_out_size) ? 
+				dev->bulk_out_size : count;
+
+	/* copy the data from userspace into our urb */
+	if (copy_from_user(dev->write_urb->transfer_buffer, buffer, 
+			   bytes_written)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	usb_skel_debug_data (__FUNCTION__, bytes_written, 
+			     dev->write_urb->transfer_buffer);
+
+	/* set up our urb */
+	FILL_BULK_URB(dev->write_urb, dev->udev, 
+		      usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+		      dev->write_urb->transfer_buffer, bytes_written,
+		      skel_write_bulk_callback, dev);
+
+	/* send the data out the bulk port */
+	retval = usb_submit_urb(dev->write_urb);
+	if (retval) {
+		err(__FUNCTION__ " - failed submitting write urb, error %d",
+		    retval);
+	} else {
+		retval = bytes_written;
+	}
+
+exit:
+	/* unlock the device */
+	up (&dev->sem);
+
+	return retval;
+}
+
+
+/**
+ *	skel_ioctl
+ */
+static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_skel *dev;
+
+	dev = (struct usb_skel *)file->private_data;
+
+	/* lock this object */
+	down (&dev->sem);
+
+	/* verify that the device wasn't unplugged */
+	if (dev->udev == NULL) {
+		up (&dev->sem);
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - minor %d, cmd 0x%.4x, arg %ld", 
+	    dev->minor, cmd, arg);
+
+
+	/* fill in your device specific stuff here */
+	
+	/* unlock the device */
+	up (&dev->sem);
+	
+	/* return that we did not understand this ioctl call */
+	return -ENOTTY;
+}
+
+
+/**
+ *	skel_write_bulk_callback
+ */
+static void skel_write_bulk_callback (struct urb *urb)
+{
+	struct usb_skel *dev = (struct usb_skel *)urb->context;
+
+	dbg(__FUNCTION__ " - minor %d", dev->minor);
+
+	if ((urb->status != -ENOENT) && 
+	    (urb->status != -ECONNRESET)) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+		    urb->status);
+		return;
+	}
+
+	return;
+}
+
+
+
+
+
+static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_skel *dev = NULL;
+	struct usb_interface *interface;
+	struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int minor;
+	int buffer_size;
+	int i;
+	char name[10];
+
+	
+	/* See if the device offered us matches what we can accept */
+	if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
+	    (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
+		return NULL;
+	}
+
+	/* select a "subminor" number (part of a minor number) */
+	down (&minor_table_mutex);
+	for (minor = 0; minor < MAX_DEVICES; i++) {
+		if (minor_table[minor] == NULL)
+			break;
+	}
+	if (minor >= MAX_DEVICES) {
+		info ("Too many devices plugged in, can not handle this device.");
+		goto exit;
+	}
+
+	/* allocate memory for our device state and intialize it */
+	dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL);
+	if (dev == NULL) {
+		err ("Out of memory");
+		goto exit;
+	}
+	minor_table[minor] = dev;
+
+	interface = &udev->actconfig->interface[ifnum];
+
+	init_MUTEX (&dev->sem);
+	dev->udev = udev;
+	dev->interface = interface;
+	dev->minor = minor;
+
+	/* set up the endpoint information */
+	/* check out the endpoints */
+	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 */
+			buffer_size = endpoint->wMaxPacketSize;
+			dev->bulk_in_size = buffer_size;
+			dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+			dev->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+			if (!dev->bulk_in_buffer) {
+				err("Couldn't allocate bulk_in_buffer");
+				goto error;
+			}
+		}
+		
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk out endpoint */
+			dev->write_urb = usb_alloc_urb(0);
+			if (!dev->write_urb) {
+				err("No free urbs available");
+				goto error;
+			}
+			buffer_size = endpoint->wMaxPacketSize;
+			dev->bulk_out_size = buffer_size;
+			dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+			dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+			if (!dev->bulk_out_buffer) {
+				err("Couldn't allocate bulk_out_buffer");
+				goto error;
+			}
+			FILL_BULK_URB(dev->write_urb, udev, 
+				      usb_sndbulkpipe(udev, 
+						      endpoint->bEndpointAddress),
+				      dev->bulk_out_buffer, buffer_size,
+				      skel_write_bulk_callback, dev);
+		}
+	}
+
+	/* initialize the devfs node for this device and register it */
+	sprintf(name, "skel%d", dev->minor);
+	
+	dev->devfs = devfs_register (usb_devfs_handle, name,
+				     DEVFS_FL_DEFAULT, USB_MAJOR,
+				     USB_SKEL_MINOR_BASE + dev->minor,
+				     S_IFCHR | S_IRUSR | S_IWUSR | 
+				     S_IRGRP | S_IWGRP | S_IROTH, 
+				     &skel_fops, NULL);
+
+	/* let the user know what node this device is now attached to */
+	info ("USB Skeleton device now attached to USBSkel%d", dev->minor);
+	goto exit;
+	
+error:
+	minor_table [dev->minor] = NULL;
+	if (dev->bulk_in_buffer != NULL)
+		kfree (dev->bulk_in_buffer);
+	if (dev->bulk_out_buffer != NULL)
+		kfree (dev->bulk_out_buffer);
+	if (dev->write_urb != NULL)
+		usb_free_urb (dev->write_urb);
+	kfree (dev);
+	dev = NULL;
+
+exit:
+	up (&minor_table_mutex);
+	return dev;
+}
+
+
+/**
+ *	skel_disconnect
+ */
+static void skel_disconnect(struct usb_device *udev, void *ptr)
+{
+	struct usb_skel *dev;
+	int minor;
+
+	dev = (struct usb_skel *)ptr;
+	
+	down (&minor_table_mutex);
+	down (&dev->sem);
+		
+	minor = dev->minor;
+
+	/* if the device is not opened, then we clean up right now */
+	if (!dev->open_count) {
+		minor_table[dev->minor] = NULL;
+		if (dev->bulk_in_buffer != NULL)
+			kfree (dev->bulk_in_buffer);
+		if (dev->bulk_out_buffer != NULL)
+			kfree (dev->bulk_out_buffer);
+		if (dev->write_urb != NULL)
+			usb_free_urb (dev->write_urb);
+		kfree (dev);
+	} else {
+		dev->udev = NULL;
+		up (&dev->sem);
+	}
+
+	/* remove our devfs node */
+	devfs_unregister(dev->devfs);
+
+	info("USB Skeleton #%d now disconnected", minor);
+	up (&minor_table_mutex);
+}
+
+
+
+/**
+ *	usb_skel_init
+ */
+static int __init usb_skel_init(void)
+{
+	int result;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&skel_driver);
+	if (result < 0) {
+		err("usb_register failed for the "__FILE__" driver. Error number %d",
+		    result);
+		return -1;
+	}
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+
+/**
+ *	usb_skel_exit
+ */
+static void __exit usb_skel_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&skel_driver);
+}
+
+
+module_init (usb_skel_init);
+module_exit (usb_skel_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
diff -u --recursive --new-file v2.4.6/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.6/linux/drivers/usb/usb.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/usb.c	Wed Jul  4 20:11:17 2001
@@ -29,6 +29,7 @@
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/spinlock.h>
 
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
@@ -59,6 +60,7 @@
  */
 LIST_HEAD(usb_driver_list);
 LIST_HEAD(usb_bus_list);
+rwlock_t usb_bus_list_lock = RW_LOCK_UNLOCKED;
 
 devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
 
@@ -110,6 +112,7 @@
 {
 	struct list_head *tmp;
 
+	read_lock_irq (&usb_bus_list_lock);
 	tmp = usb_bus_list.next;
 	while (tmp != &usb_bus_list) {
 		struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
@@ -117,6 +120,7 @@
 		tmp = tmp->next;
 		usb_check_support(bus->root_hub);
 	}
+	read_unlock_irq (&usb_bus_list_lock);
 }
 
 /*
@@ -178,6 +182,7 @@
 	 */
 	list_del(&driver->driver_list);
 
+	read_lock_irq (&usb_bus_list_lock);
 	tmp = usb_bus_list.next;
 	while (tmp != &usb_bus_list) {
 		struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
@@ -185,6 +190,7 @@
 		tmp = tmp->next;
 		usb_drivers_purge(driver, bus->root_hub);
 	}
+	read_unlock_irq (&usb_bus_list_lock);
 }
 
 struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
@@ -415,6 +421,7 @@
 {
 	int busnum;
 
+	write_lock_irq (&usb_bus_list_lock);
 	busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);
 	if (busnum < USB_MAXBUS) {
 		set_bit(busnum, busmap.busmap);
@@ -426,6 +433,7 @@
 
 	/* Add it to the list of buses */
 	list_add(&bus->bus_list, &usb_bus_list);
+	write_unlock_irq (&usb_bus_list_lock);
 
 	usbdevfs_add_bus(bus);
 
@@ -447,9 +455,11 @@
 	 * controller code, as well as having it call this when cleaning
 	 * itself up
 	 */
+	write_lock_irq (&usb_bus_list_lock);
 	list_del(&bus->bus_list);
+	write_unlock_irq (&usb_bus_list_lock);
 
-	usbdevfs_remove_bus(bus);
+       usbdevfs_remove_bus(bus);
 
 	clear_bit(bus->busnum, busmap.busmap);
 
diff -u --recursive --new-file v2.4.6/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- v2.4.6/linux/drivers/video/cyber2000fb.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/video/cyber2000fb.c	Wed Jul  4 11:50:39 2001
@@ -367,6 +367,7 @@
 	 * Other
 	 */
 	u_char	palette_ctrl;
+	u_int	vmode;
 };
 
 static const u_char crtc_idx[] = {
@@ -427,6 +428,16 @@
 	cyber2000_attrw(0x13, 0x00);
 	cyber2000_attrw(0x14, 0x00);
 
+	/* woody: set the interlaced bit... */
+	/* FIXME: what about doublescan? */
+	cyber2000_outb(0x11, 0x3ce);
+	i = cyber2000_inb(0x3cf);
+	if (hw->vmode == FB_VMODE_INTERLACED)
+		i |= 0x20;
+	else
+		i &= ~0x20;
+	cyber2000_outb(i, 0x3cf);
+
 	/* PLL registers */
 	cyber2000_grphw(DCLK_MULT, hw->clock_mult);
 	cyber2000_grphw(DCLK_DIV,  hw->clock_div);
@@ -711,6 +722,7 @@
 
 	hw->width = var->xres_virtual;
 	hw->palette_ctrl = 0x06;
+	hw->vmode = var->vmode;
 
 	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
@@ -1570,7 +1582,7 @@
 	/*
 	 * Our driver data
 	 */
-	dev->driver_data = cfb;
+	pci_set_drvdata(dev, cfb);
 	if (int_cfb_info == NULL)
 		int_cfb_info = cfb;
 
@@ -1586,7 +1598,7 @@
 
 static void __devexit cyberpro_remove(struct pci_dev *dev)
 {
-	struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
+	struct cfb_info *cfb = pci_get_drvdata(dev);
 
 	if (cfb) {
 		/*
@@ -1606,7 +1618,7 @@
 		 * Ensure that the driver data is no longer
 		 * valid.
 		 */
-		dev->driver_data = NULL;
+		pci_set_drvdata(dev, NULL);
 		if (cfb == int_cfb_info)
 			int_cfb_info = NULL;
 	}
@@ -1622,7 +1634,7 @@
  */
 static int cyberpro_resume(struct pci_dev *dev)
 {
-	struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
+	struct cfb_info *cfb = pci_get_drvdata(dev);
 
 	if (cfb) {
 		cyberpro_init_hw(cfb, 0);
diff -u --recursive --new-file v2.4.6/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.4.6/linux/drivers/video/fbcon.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/video/fbcon.c	Wed Jul  4 22:56:00 2001
@@ -31,6 +31,8 @@
  *
  *  Random hacking by Martin Mares <mj@ucw.cz>
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
  *
  *  The low level operations for the various display memory organizations are
  *  now in separate source files.
@@ -239,6 +241,20 @@
       add_timer(&cursor_timer);
 }
 
+
+/**
+ *	PROC_CONSOLE - find the attached tty or visible console
+ *	@info: frame buffer info structure
+ *
+ *	Finds the tty attached to the process or visible console if
+ *	the process is not directly attached to a tty (e.g. remote
+ *	user) for device @info.
+ *
+ *	Returns -1 errno on error, or tty/visible console number
+ *	on success.
+ *
+ */
+
 int PROC_CONSOLE(const struct fb_info *info)
 {
         int fgc;
@@ -261,6 +277,21 @@
         return MINOR(current->tty->device) - 1;
 }
 
+
+/**
+ *	set_all_vcs - set all virtual consoles to match
+ *	@fbidx: frame buffer index (e.g. fb0, fb1, ...)
+ *	@fb: frame buffer ops structure
+ *	@var: frame buffer screen structure to set
+ *	@info: frame buffer info structure
+ *
+ *	Set all virtual consoles to match screen info set in @var
+ *	for device @info.
+ *
+ *	Returns negative errno on error, or zero on success.
+ *
+ */
+
 int set_all_vcs(int fbidx, struct fb_ops *fb, struct fb_var_screeninfo *var,
                 struct fb_info *info)
 {
@@ -277,6 +308,17 @@
     return 0;
 }
 
+
+/**
+ *	set_con2fb_map - map console to frame buffer device
+ *	@unit: virtual console number to map
+ *	@newidx: frame buffer index to map virtual console to
+ *
+ *	Maps a virtual console @unit to a frame buffer device
+ *	@newidx.
+ *
+ */
+
 void set_con2fb_map(int unit, int newidx)
 {
     int oldidx = con2fb_map[unit];
@@ -1124,6 +1166,20 @@
     }
 }
 
+/**
+ *	fbcon_redraw_clear - clear area of the screen
+ *	@conp: stucture pointing to current active virtual console
+ *	@p: display structure
+ *	@sy: starting Y coordinate
+ *	@sx: starting X coordinate
+ *	@height: height of area to clear
+ *	@width: width of area to clear
+ *
+ *	Clears a specified area of the screen.  All dimensions are in
+ *	pixels.
+ *
+ */
+
 void fbcon_redraw_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 		     int height, int width)
 {
@@ -1133,7 +1189,25 @@
 	    fbcon_putc(conp, ' ', sy+y, sx+x);
 }
 
-/* This cannot be used together with ypan or ywrap */
+
+/**
+ *	fbcon_redraw_bmove - copy area of screen to another area
+ *	@p: display structure
+ *	@sy: origin Y coordinate
+ *	@sx: origin X coordinate
+ *	@dy: destination Y coordinate
+ *	@dx: destination X coordinate
+ *	@h: height of area to copy
+ *	@w: width of area to copy
+ *
+ *	Copies an area of the screen to another area of the same screen.
+ *	All dimensions are in pixels.
+ *
+ *	Note that this function cannot be used together with ypan or
+ *	ywrap.
+ *
+ */
+
 void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h, int w)
 {
     if (sy != dy)
diff -u --recursive --new-file v2.4.6/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- v2.4.6/linux/drivers/video/hgafb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/hgafb.c	Fri Jul  6 16:48:50 2001
@@ -49,7 +49,7 @@
 
 #ifdef MODULE
 
-#define INCLUDE_LINUX_LOGOBW
+#define INCLUDE_LINUX_LOGO_DATA
 #include <linux/linux_logo.h>
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.4.6/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.4.6/linux/drivers/video/imsttfb.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/video/imsttfb.c	Sun Jul  8 13:17:30 2001
@@ -386,7 +386,6 @@
 #if defined(CONFIG_PPC)
 static signed char init_vmode __initdata = -1, init_cmode __initdata = -1;
 #endif
-static struct fb_info_imstt *fb_info_imstt_p[FB_MAX] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
 static struct imstt_regvals tvp_reg_init_2 = {
 	512,
@@ -444,6 +443,12 @@
 	{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
 };
 
+/*
+ * PCI driver prototypes
+ */
+static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void imsttfb_remove(struct pci_dev *pdev);
+
 static __u32
 getclkMHz (struct fb_info_imstt *p)
 {
@@ -1273,10 +1278,11 @@
 				break;
 #endif
 #ifdef FBCON_HAS_CFB32
-			case 32:
-				i = (regno << 8) | regno;
+			case 32: {
+				int i = (regno << 8) | regno;
 				p->fbcon_cmap.cfb32[regno] = (i << 16) | i;
 				break;
+			}
 #endif
 		}
 
@@ -1623,6 +1629,23 @@
 	}
 }
 
+static struct pci_device_id imsttfb_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT128,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, IBM },
+	{ PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT3D,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TVP },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl);
+
+static struct pci_driver imsttfb_pci_driver = {
+	name:		"imsttfb",
+	id_table:	imsttfb_pci_tbl,
+	probe:		imsttfb_probe,
+	remove:		imsttfb_remove,
+};
+
 static struct fb_ops imsttfb_ops = {
 	owner:		THIS_MODULE,
 	fb_get_fix:	imsttfb_get_fix,
@@ -1869,7 +1892,6 @@
 	printk("fb%u: %s frame buffer; %uMB vram; chip version %u\n",
 		i, p->fix.id, p->total_vram >> 20, tmp);
 
-	fb_info_imstt_p[i] = p;
 #ifdef CONFIG_FB_COMPAT_XPMAC
 	strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
 	display_info.fb_address = p->frame_buffer_phys;
@@ -1881,61 +1903,69 @@
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
-int __init 
-imsttfb_init(void)
+static int __devinit
+imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	int i;
-	struct pci_dev *pdev = NULL;
 	struct fb_info_imstt *p;
 	unsigned long addr, size;
 
-	while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
-		if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
-			continue;
-		if (pci_enable_device(pdev))
-			continue;
-
-		addr = pci_resource_start (pdev, 0);
-		size = pci_resource_len (pdev, 0);
-		if (!addr)
-			continue;
-
-		p = kmalloc(sizeof(struct fb_info_imstt), GFP_ATOMIC);
-		if (!p)
-			continue;
-		memset(p, 0, sizeof(struct fb_info_imstt));
-
-		if (!request_mem_region(addr, size, "imsttfb")) {
-			kfree(p);
-			continue;
-		}
-		printk("imsttfb: device=%04x\n", pdev->device);
-
-		switch (pdev->device) {
-			case 0x9128:	/* IMS,tt128mbA */
-				p->ramdac = IBM;
-				break;
-			case 0x9135:	/* IMS,tt3d */
-			default:
-				p->ramdac = TVP;
-				break;
-		}
+	addr = pci_resource_start (pdev, 0);
+	size = pci_resource_len (pdev, 0);
 
-		p->frame_buffer_phys = addr;
-		p->board_size = size;
-		p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
-		p->dc_regs_phys = addr + 0x800000;
-		p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
-		p->cmap_regs_phys = addr + 0x840000;
-		p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
+	p = kmalloc(sizeof(struct fb_info_imstt), GFP_KERNEL);
 
-		init_imstt(p);
+	if (!p) {
+		printk(KERN_ERR "imsttfb: Can't allocate memory\n");
+		return -ENOMEM;
 	}
-	for (i = 0; i < FB_MAX; i++) {
-		if (fb_info_imstt_p[i])
-			return 0;
+
+	memset(p, 0, sizeof(struct fb_info_imstt));
+
+	if (!request_mem_region(addr, size, "imsttfb")) {
+		printk(KERN_ERR "imsttfb: Can't reserve memory region\n");
+		kfree(p);
+		return -ENODEV;
 	}
-	return -ENXIO;
+
+	switch (pdev->device) {
+		case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */
+			p->ramdac = IBM;
+			break;
+		case PCI_DEVICE_ID_IMS_TT3D:  /* IMS,tt3d */
+			p->ramdac = TVP;
+			break;
+		default:
+			printk(KERN_INFO "imsttfb: Device 0x%lx unknown, "
+					 "contact maintainer.\n", pdev->device);
+			return -ENODEV;
+	}
+
+	p->frame_buffer_phys = addr;
+	p->board_size = size;
+	p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
+	p->dc_regs_phys = addr + 0x800000;
+	p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
+	p->cmap_regs_phys = addr + 0x840000;
+	p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
+
+	init_imstt(p);
+
+	pdev->driver_data = p;
+
+	return 0;
+}
+
+static void __devexit
+imsttfb_remove(struct pci_dev *pdev)
+{
+	struct fb_info_imstt *p = (struct fb_info_imstt *)pdev->driver_data;
+
+	unregister_framebuffer(&p->info);
+	iounmap(p->cmap_regs);
+	iounmap(p->dc_regs);
+	iounmap(p->frame_buffer);
+	release_mem_region(p->frame_buffer_phys, p->board_size);
+	kfree(p);
 }
 
 #ifndef MODULE
@@ -1996,29 +2026,20 @@
 	return 0;
 }
 
-#else /* MODULE */
-static void __exit
-imsttfb_exit(void)
-{
-	struct fb_info_imstt *p;
-	__u32 i;
+#endif /* MODULE */
 
-	for (i = 0; i < FB_MAX; i++) {
-		p = fb_info_imstt_p[i];
-		if (!p)
-			continue;
-		unregister_framebuffer(&p->info);
-		iounmap(p->cmap_regs);
-		iounmap(p->dc_regs);
-		iounmap(p->frame_buffer);
-		release_mem_region(p->frame_buffer_phys, p->board_size);
-		kfree(p);
-	}
+int __init imsttfb_init(void)
+{
+	return pci_module_init(&imsttfb_pci_driver);
+}
+ 
+static void __exit imsttfb_exit(void)
+{
+	pci_unregister_driver(&imsttfb_pci_driver);
 }
 
-#include "macmodes.c"
-
+#ifdef MODULE
 module_init(imsttfb_init);
+#endif
 module_exit(imsttfb_exit);
-#endif /* MODULE */
 
diff -u --recursive --new-file v2.4.6/linux/drivers/video/maxinefb.c linux/drivers/video/maxinefb.c
--- v2.4.6/linux/drivers/video/maxinefb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/maxinefb.c	Wed Jul  4 11:50:39 2001
@@ -272,14 +272,6 @@
 	return 0;
 }
 
-
-static int maxinefb_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg, int con,
-			  struct fb_info *info)
-{
-	return -EINVAL;
-}
-
 static int maxinefb_switch(int con, struct fb_info *info)
 {
 	maxinefb_do_fb_set_var(&fb_display[con].var, 1);
@@ -287,22 +279,6 @@
 	return 0;
 }
 
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
-static void maxinefb_blank(int blank, struct fb_info *info)
-{
-	/* Not supported */
-}
-
-static int maxinefb_open(struct fb_info *info, int user)
-{
-	/*
-	 * Nothing, only a usage count for the moment
-	 */
-	MOD_INC_USE_COUNT;
-	return (0);
-}
-
 static void maxinefb_set_disp(int con)
 {
 	struct fb_fix_screeninfo fix;
@@ -329,31 +305,28 @@
 	display->dispsw = &fbcon_cfb8;
 }
 
-static int maxinefb_release(struct fb_info *info, int user)
-{
-	MOD_DEC_USE_COUNT;
-	return (0);
-}
-
 static struct fb_ops maxinefb_ops = {
-	owner:THIS_MODULE,
-	fb_open:maxinefb_open,
-	fb_release:maxinefb_release,
-	fb_get_fix:maxinefb_get_fix,
-	fb_get_var:maxinefb_get_var,
-	fb_set_var:maxinefb_set_var,
-	fb_get_cmap:maxinefb_get_cmap,
-	fb_set_cmap:maxinefb_set_cmap,
-	fb_ioctl:maxinefb_ioctl,
-	fb_mmap:0,
-	fb_rasterimg:0
+	owner:		THIS_MODULE,
+	fb_get_fix:	maxinefb_get_fix,
+	fb_get_var:	maxinefb_get_var,
+	fb_set_var:	maxinefb_set_var,
+	fb_get_cmap:	maxinefb_get_cmap,
+	fb_set_cmap:	maxinefb_set_cmap,
 };
 
-int __init maxinefb_init_one()
+int __init maxinefb_init(void)
 {
 	volatile unsigned char *fboff;
 	int i;
 
+	/* Validate we're on the proper machine type */
+	if (mips_machtype != MACH_DS5000_XX) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "Maxinefb: Personal DECstation detected\n");
+	printk(KERN_INFO "Maxinefb: initializing onboard framebuffer\n");
+
 	/* Framebuffer display memory base address */
 	fb_start = DS5000_xx_ONBOARD_FBMEM_START;
 
@@ -390,7 +363,7 @@
 	fb_info.disp = &disp;
 	fb_info.switch_con = &maxinefb_switch;
 	fb_info.updatevar = &maxinefb_fb_update_var;
-	fb_info.blank = &maxinefb_blank;
+	fb_info.blank = NULL;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
 	maxinefb_do_fb_set_var(&maxinefb_defined, 1);
 
@@ -403,23 +376,13 @@
 	return 0;
 }
 
-
-/* Initialise the framebuffer */
-
-void __init maxinefb_init()
+static void __exit maxinefb_exit(void)
 {
-	unsigned int sid;
-
-	if (mips_machtype == MACH_DS5000_XX) {
-		printk("Maxinefb: Personal DECstation detected\n");
-		printk("Maxinefb: initializing onboard framebuffer\n");
-
-		maxinefb_init_one();
-
-	}
-
+	unregister_framebuffer(&fb_info);
 }
 
-void __init maxinefb_setup(char *options, int *ints)
-{
-}
+#ifdef MODULE
+module_init(maxinefb_init);
+#endif
+module_exit(maxinefb_exit);
+
diff -u --recursive --new-file v2.4.6/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.4.6/linux/drivers/video/tdfxfb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/tdfxfb.c	Wed Jul  4 11:50:39 2001
@@ -1207,7 +1207,7 @@
    revc:		tdfx_cfbX_revc,   
    cursor:		tdfx_cfbX_cursor, 
    clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTH(8)
+   fontwidthmask:	FONTWIDTHRANGE(8, 12)
 };
 #endif
 #ifdef FBCON_HAS_CFB16
@@ -1220,7 +1220,7 @@
    revc:		tdfx_cfbX_revc, 
    cursor:		tdfx_cfbX_cursor, 
    clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTH(8)
+   fontwidthmask:	FONTWIDTHRANGE(8, 12)
 };
 #endif
 #ifdef FBCON_HAS_CFB24
@@ -1233,7 +1233,7 @@
    revc:		tdfx_cfbX_revc, 
    cursor:		tdfx_cfbX_cursor, 
    clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTH(8)
+   fontwidthmask:	FONTWIDTHRANGE(8, 12)
 };
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -1246,7 +1246,7 @@
    revc:		tdfx_cfbX_revc, 
    cursor:		tdfx_cfbX_cursor, 
    clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTH(8)
+   fontwidthmask:	FONTWIDTHRANGE(8, 12)
 };
 #endif
 
@@ -1892,7 +1892,7 @@
        ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
 	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3) ||
 	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO5))) {
-      char *name;
+      char *name = NULL;
 
       fb_info.dev   = pdev->device;
       switch (pdev->device) {
@@ -2314,7 +2314,12 @@
    unsigned int h,to;
 
    tdfxfb_createcursorshape(p);
-   xline = (1 << fb_info.cursor.w)-1;
+   xline = ~((1 << (32 - fb_info.cursor.w)) - 1);
+
+#ifdef __LITTLE_ENDIAN
+   xline = swab32(xline);
+#endif
+
    cursorbase=(u8*)fb_info.bufbase_virt;
    h=fb_info.cursor.cursorimage;     
    
diff -u --recursive --new-file v2.4.6/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.4.6/linux/drivers/video/tgafb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/tgafb.c	Wed Jul  4 14:41:33 2001
@@ -60,7 +60,7 @@
 static int current_par_valid = 0;
 static struct display disp;
 
-static char default_fontname[40] = { 0 };
+static char default_fontname[40] __initdata = { 0 };
 static struct fb_var_screeninfo default_var;
 static int default_var_valid = 0;
 
@@ -281,9 +281,9 @@
 static void tgafb_set_disp(const void *fb_par, struct display *disp, 
 		struct fb_info_gen *info);
 
+#ifndef MODULE
 int tgafb_setup(char*);
-int tgafb_init(void);
-void tgafb_cleanup(struct fb_info *info);
+#endif
 
 static void tgafb_set_pll(int f);
 #if 1
@@ -879,6 +879,7 @@
 };
 
 
+#ifndef MODULE
     /*
      *  Setup
      */
@@ -910,6 +911,7 @@
     }
     return 0;
 }
+#endif
 
 
     /*
@@ -990,9 +992,9 @@
      *  Cleanup
      */
 
-void tgafb_cleanup(struct fb_info *info)
+void __exit tgafb_cleanup(void)
 {
-    unregister_framebuffer(info);
+    unregister_framebuffer(&fb_info.gen.info);
 }
 
 
@@ -1001,14 +1003,7 @@
      */
 
 #ifdef MODULE
-int init_module(void)
-{
-    return tgafb_init();
-}
-
-void cleanup_module(void)
-{
-    tgafb_cleanup(void);
-}
-#endif /* MODULE */
+module_init(tgafb_init);
+#endif
 
+module_exit(tgafb_cleanup);
diff -u --recursive --new-file v2.4.6/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.6/linux/fs/buffer.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/buffer.c	Sun Jul  8 14:32:31 2001
@@ -71,6 +71,9 @@
 
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
 
+#define get_bh(bh)	atomic_inc(&(bh)->b_count)
+#define put_bh(bh)	atomic_dec(&(bh)->b_count)
+
 /*
  * Hash table gook..
  */
@@ -133,6 +136,21 @@
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 100, 0, 0};
 
+static inline void __unlock_buffer(struct buffer_head *bh)
+{
+	clear_bit(BH_Lock, &bh->b_state);
+	smp_mb__after_clear_bit();
+	if (waitqueue_active(&bh->b_wait))
+		wake_up(&bh->b_wait);
+}
+
+void unlock_buffer(struct buffer_head *bh)
+{
+	get_bh(bh);
+	__unlock_buffer(bh);
+	put_bh(bh);
+}
+
 /*
  * Rewrote the wait-routines to use the "new" wait-queue functionality,
  * and getting rid of the cli-sti pairs. The wait-queue routines still
@@ -147,7 +165,7 @@
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	atomic_inc(&bh->b_count);
+	get_bh(bh);
 	add_wait_queue(&bh->b_wait, &wait);
 	do {
 		run_task_queue(&tq_disk);
@@ -158,14 +176,15 @@
 	} while (buffer_locked(bh));
 	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&bh->b_wait, &wait);
-	atomic_dec(&bh->b_count);
+	put_bh(bh);
 }
 
 /* End-of-write handler.. Just mark it up-to-date and unlock the buffer. */
 static void end_buffer_write(struct buffer_head *bh, int uptodate)
 {
 	mark_buffer_uptodate(bh, uptodate);
-	unlock_buffer(bh);
+	__unlock_buffer(bh);
+	put_bh(bh);
 }
 
 /*
@@ -179,14 +198,14 @@
 static void write_locked_buffers(struct buffer_head **array, unsigned int count)
 {
 	struct buffer_head *wait = *array;
-	atomic_inc(&wait->b_count);
+	get_bh(wait);
 	do {
 		struct buffer_head * bh = *array++;
 		bh->b_end_io = end_buffer_write;
 		submit_bh(WRITE, bh);
 	} while (--count);
 	wait_on_buffer(wait);
-	atomic_dec(&wait->b_count);
+	put_bh(wait);
 }
 
 #define NRSYNC (32)
@@ -210,6 +229,7 @@
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
+		get_bh(bh);
 		if (atomic_set_buffer_clean(bh)) {
 			__refile_buffer(bh);
 			array[count++] = bh;
@@ -220,7 +240,8 @@
 			write_locked_buffers(array, count);
 			goto repeat;
 		}
-		unlock_buffer(bh);
+		__unlock_buffer(bh);
+		put_bh(bh);
 	}
 	spin_unlock(&lru_list_lock);
 
@@ -249,10 +270,10 @@
 		if (dev && bh->b_dev != dev)
 			continue;
 
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 		spin_unlock(&lru_list_lock);
 		wait_on_buffer (bh);
-		atomic_dec(&bh->b_count);
+		put_bh(bh);
 		goto repeat;
 	}
 	spin_unlock(&lru_list_lock);
@@ -552,7 +573,7 @@
 		    bh->b_dev     == dev)
 			break;
 	if (bh)
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 
 	return bh;
 }
@@ -646,12 +667,12 @@
 			if (!bh->b_pprev)
 				continue;
 			if (buffer_locked(bh)) {
-				atomic_inc(&bh->b_count);
+				get_bh(bh);
 				spin_unlock(&lru_list_lock);
 				wait_on_buffer(bh);
 				slept = 1;
 				spin_lock(&lru_list_lock);
-				atomic_dec(&bh->b_count);
+				put_bh(bh);
 			}
 
 			write_lock(&hash_table_lock);
@@ -711,12 +732,12 @@
 			if (!bh->b_pprev)
 				continue;
 			if (buffer_locked(bh)) {
-				atomic_inc(&bh->b_count);
+				get_bh(bh);
 				spin_unlock(&lru_list_lock);
 				wait_on_buffer(bh);
 				slept = 1;
 				spin_lock(&lru_list_lock);
-				atomic_dec(&bh->b_count);
+				put_bh(bh);
 			}
 
 			write_lock(&hash_table_lock);
@@ -802,8 +823,7 @@
 	 * that unlock the page..
 	 */
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	unlock_buffer(bh);
-	atomic_dec(&bh->b_count);
+	__unlock_buffer(bh);
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
 		if (tmp->b_end_io == end_buffer_io_async && buffer_locked(tmp))
@@ -813,6 +833,7 @@
 
 	/* OK, the async IO on this page is complete. */
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	put_bh(bh);
 
 	/*
 	 * if none of the buffers had errors then we can set the
@@ -832,6 +853,7 @@
 	return;
 
 still_busy:
+	put_bh(bh);
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
 	return;
 }
@@ -879,7 +901,7 @@
 			bh->b_inode = &tmp;
 			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
 			if (buffer_dirty(bh)) {
-				atomic_inc(&bh->b_count);
+				get_bh(bh);
 				spin_unlock(&lru_list_lock);
 				ll_rw_block(WRITE, 1, &bh);
 				brelse(bh);
@@ -891,7 +913,7 @@
 	while (!list_empty(&tmp.i_dirty_buffers)) {
 		bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
 		remove_inode_queue(bh);
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 		spin_unlock(&lru_list_lock);
 		wait_on_buffer(bh);
 		if (!buffer_uptodate(bh))
@@ -935,7 +957,7 @@
 	     bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
 	     list = bh->b_inode_buffers.prev) {
 		if (buffer_locked(bh)) {
-			atomic_inc(&bh->b_count);
+			get_bh(bh);
 			spin_unlock(&lru_list_lock);
 			wait_on_buffer(bh);
 			if (!buffer_uptodate(bh))
@@ -1130,7 +1152,7 @@
 void __brelse(struct buffer_head * buf)
 {
 	if (atomic_read(&buf->b_count)) {
-		atomic_dec(&buf->b_count);
+		put_bh(buf);
 		return;
 	}
 	printk("VFS: brelse: Trying to free free buffer\n");
@@ -1528,7 +1550,7 @@
 	do {
 		lock_buffer(bh);
 		bh->b_end_io = end_buffer_io_async;
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 		set_bit(BH_Uptodate, &bh->b_state);
 		clear_bit(BH_Dirty, &bh->b_state);
 		bh = bh->b_this_page;
@@ -1536,8 +1558,9 @@
 
 	/* Stage 3: submit the IO */
 	do {
+		struct buffer_head *next = bh->b_this_page;
 		submit_bh(WRITE, bh);
-		bh = bh->b_this_page;		
+		bh = next;
 	} while (bh != head);
 
 	/* Done - end_buffer_io_async will unlock */
@@ -1729,7 +1752,7 @@
 		struct buffer_head * bh = arr[i];
 		lock_buffer(bh);
 		bh->b_end_io = end_buffer_io_async;
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 	}
 
 	/* Stage 3: start the IO */
@@ -1982,7 +2005,8 @@
 	mark_buffer_uptodate(bh, uptodate);
 
 	kiobuf = bh->b_private;
-	unlock_buffer(bh);
+	__unlock_buffer(bh);
+	put_bh(bh);
 	end_kio_request(kiobuf, uptodate);
 }
 
@@ -2107,7 +2131,7 @@
 				offset += size;
 
 				atomic_inc(&iobuf->io_count);
-
+				get_bh(tmp);
 				submit_bh(rw, tmp);
 				/* 
 				 * Wait for IO if we have got too much 
@@ -2175,14 +2199,15 @@
 		bh->b_blocknr = *(b++);
 		set_bit(BH_Mapped, &bh->b_state);
 		bh->b_end_io = end_buffer_io_async;
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 		bh = bh->b_this_page;
 	} while (bh != head);
 
 	/* Stage 2: start the IO */
 	do {
+		struct buffer_head *next = bh->b_this_page;
 		submit_bh(rw, bh);
-		bh = bh->b_this_page;
+		bh = next;
 	} while (bh != head);
 	return 0;
 }
@@ -2554,10 +2579,10 @@
 		}
 
 		/* OK, now we are committed to write it out. */
-		atomic_inc(&bh->b_count);
+		get_bh(bh);
 		spin_unlock(&lru_list_lock);
 		ll_rw_block(WRITE, 1, &bh);
-		atomic_dec(&bh->b_count);
+		put_bh(bh);
 
 		if (current->need_resched)
 			schedule();
diff -u --recursive --new-file v2.4.6/linux/fs/dcache.c linux/fs/dcache.c
--- v2.4.6/linux/fs/dcache.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/dcache.c	Thu Jul  5 10:14:23 2001
@@ -562,7 +562,7 @@
 	 * We should make sure we don't hold the superblock lock over
 	 * block allocations, but for now:
 	 */
-	if (!(gfp_mask & __GFP_IO))
+	if (!(gfp_mask & __GFP_FS))
 		return;
 
 	if (priority)
diff -u --recursive --new-file v2.4.6/linux/fs/inode.c linux/fs/inode.c
--- v2.4.6/linux/fs/inode.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/inode.c	Thu Jul  5 10:14:40 2001
@@ -692,7 +692,7 @@
 	 * want to recurse into the FS that called us
 	 * in clear_inode() and friends..
 	 */
-	if (!(gfp_mask & __GFP_IO))
+	if (!(gfp_mask & __GFP_FS))
 		return;
 
 	if (priority)
diff -u --recursive --new-file v2.4.6/linux/fs/jffs/jffs_fm.c linux/fs/jffs/jffs_fm.c
--- v2.4.6/linux/fs/jffs/jffs_fm.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/jffs/jffs_fm.c	Wed Jul  4 11:50:39 2001
@@ -47,7 +47,10 @@
 	mtd = get_mtd_device(NULL, MINOR(dev));
 
 	if (!mtd)
+	{
+		kfree(fmc);
 		return NULL;
+	}
 	
 	/* Retrieve the size of the flash memory.  */
 	fmc->flash_start = 0;
diff -u --recursive --new-file v2.4.6/linux/fs/locks.c linux/fs/locks.c
--- v2.4.6/linux/fs/locks.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/locks.c	Wed Jul  4 15:39:28 2001
@@ -112,7 +112,7 @@
  *
  *  Leases and LOCK_MAND
  *  Matthew Wilcox <willy@linuxcare.com>, June, 2000.
- *  Stephen Rothwell <sfr@linuxcare.com>, June, 2000.
+ *  Stephen Rothwell <sfr@canb.auug.org.au>, June, 2000.
  */
 
 #include <linux/slab.h>
diff -u --recursive --new-file v2.4.6/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.4.6/linux/fs/proc/proc_misc.c	Fri Apr 13 20:26:07 2001
+++ linux/fs/proc/proc_misc.c	Sat Jul  7 11:43:24 2001
@@ -146,51 +146,53 @@
  */
 #define K(x) ((x) << (PAGE_SHIFT - 10))
 #define B(x) ((x) << PAGE_SHIFT)
-        si_meminfo(&i);
-        si_swapinfo(&i);
-        len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
-                "Mem:  %8lu %8lu %8lu %8lu %8lu %8u\n"
-                "Swap: %8lu %8lu %8lu\n",
-                B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
-                B(i.sharedram), B(i.bufferram),
-                B(atomic_read(&page_cache_size)), B(i.totalswap),
-                B(i.totalswap-i.freeswap), B(i.freeswap));
-        /*
-         * Tagged format, for easy grepping and expansion.
-         * The above will go away eventually, once the tools
-         * have been updated.
-         */
-        len += sprintf(page+len,
-                "MemTotal:     %8lu kB\n"
-                "MemFree:      %8lu kB\n"
-                "MemShared:    %8lu kB\n"
-                "Buffers:      %8lu kB\n"
-                "Cached:       %8u kB\n"
+	si_meminfo(&i);
+	si_swapinfo(&i);
+	len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
+		"Mem:  %8lu %8lu %8lu %8lu %8lu %8u\n"
+		"Swap: %8lu %8lu %8lu\n",
+		B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
+		B(i.sharedram), B(i.bufferram),
+		B(atomic_read(&page_cache_size)), B(i.totalswap),
+		B(i.totalswap-i.freeswap), B(i.freeswap));
+	/*
+	 * Tagged format, for easy grepping and expansion.
+	 * The above will go away eventually, once the tools
+	 * have been updated.
+	 */
+	len += sprintf(page+len,
+		"MemTotal:     %8lu kB\n"
+		"MemFree:      %8lu kB\n"
+		"MemShared:    %8lu kB\n"
+		"Buffers:      %8lu kB\n"
+		"Cached:       %8lu kB\n"
+		"SwapCached:   %8lu kB\n"
 		"Active:       %8u kB\n"
 		"Inact_dirty:  %8u kB\n"
 		"Inact_clean:  %8u kB\n"
 		"Inact_target: %8lu kB\n"
-                "HighTotal:    %8lu kB\n"
-                "HighFree:     %8lu kB\n"
-                "LowTotal:     %8lu kB\n"
-                "LowFree:      %8lu kB\n"
-                "SwapTotal:    %8lu kB\n"
-                "SwapFree:     %8lu kB\n",
-                K(i.totalram),
-                K(i.freeram),
-                K(i.sharedram),
-                K(i.bufferram),
-                K(atomic_read(&page_cache_size)),
+		"HighTotal:    %8lu kB\n"
+		"HighFree:     %8lu kB\n"
+		"LowTotal:     %8lu kB\n"
+		"LowFree:      %8lu kB\n"
+		"SwapTotal:    %8lu kB\n"
+		"SwapFree:     %8lu kB\n",
+		K(i.totalram),
+		K(i.freeram),
+		K(i.sharedram),
+		K(i.bufferram),
+		K(atomic_read(&page_cache_size) - swapper_space.nrpages),
+		K(swapper_space.nrpages),
 		K(nr_active_pages),
 		K(nr_inactive_dirty_pages),
 		K(nr_inactive_clean_pages()),
 		K(inactive_target),
-                K(i.totalhigh),
-                K(i.freehigh),
-                K(i.totalram-i.totalhigh),
-                K(i.freeram-i.freehigh),
-                K(i.totalswap),
-                K(i.freeswap));
+		K(i.totalhigh),
+		K(i.freehigh),
+		K(i.totalram-i.totalhigh),
+		K(i.freeram-i.freehigh),
+		K(i.totalswap),
+		K(i.freeswap));
 
 	return proc_calc_metrics(page, start, off, count, eof, len);
 #undef B
@@ -289,11 +291,11 @@
 			kstat.per_cpu_nice[cpu_logical_map(i)],
 			kstat.per_cpu_system[cpu_logical_map(i)],
 			jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
-			           + kstat.per_cpu_nice[cpu_logical_map(i)] \
-			           + kstat.per_cpu_system[cpu_logical_map(i)]));
+				   + kstat.per_cpu_nice[cpu_logical_map(i)] \
+				   + kstat.per_cpu_system[cpu_logical_map(i)]));
 	len += sprintf(page + len,
 		"page %u %u\n"
-                "swap %u %u\n"
+		"swap %u %u\n"
 		"intr %u",
 			kstat.pgpgin >> 1,
 			kstat.pgpgout >> 1,
diff -u --recursive --new-file v2.4.6/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.4.6/linux/fs/sysv/dir.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/sysv/dir.c	Fri Jul  6 16:46:59 2001
@@ -211,7 +211,7 @@
 	if (err)
 		goto out_unlock;
 	memcpy (de->name, name, namelen);
-	memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen);
+	memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
 	de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
 	err = dir_commit_chunk(page, from, to);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.4.6/linux/include/asm-arm/arch-ebsa285/io.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-arm/arch-ebsa285/io.h	Wed Jul  4 20:11:17 2001
@@ -48,16 +48,7 @@
 #define __arch_getw(a)		(*(volatile unsigned short *)(a))
 #define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
 
-#include <asm/hardware/dec21285.h>
-
-/*
- * ioremap support - validate a PCI memory address,
- * and convert a PCI memory address to a physical
- * address for the page tables.
- */
-#define iomem_valid_addr(iomem,sz) \
-	((iomem) < 0x80000000 && (iomem) + (sz) <= 0x80000000)
-
-#define iomem_to_phys(iomem)	((iomem) + DC21285_PCI_MEM)
+#define iomem_valid_addr(iomem,sz)	(1)
+#define iomem_to_phys(iomem)		(iomem)
 
 #endif
diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/arch-integrator/io.h linux/include/asm-arm/arch-integrator/io.h
--- v2.4.6/linux/include/asm-arm/arch-integrator/io.h	Fri Mar  2 18:38:39 2001
+++ linux/include/asm-arm/arch-integrator/io.h	Wed Jul  4 20:11:17 2001
@@ -35,12 +35,11 @@
 /*
  * Validate the pci memory address for ioremap.
  */
-#define iomem_valid_addr(iomem,size)	\
-	((iomem) > 0 && (iomem) + (size) <= 0x20000000)
+#define iomem_valid_addr(iomem,size)	(1)
 
 /*
  * Convert PCI memory space to a CPU physical address
  */
-#define iomem_to_phys(iomem)	((iomem) + PHYS_PCI_MEM_BASE)
+#define iomem_to_phys(iomem)	(iomem)
 
 #endif
diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.4.6/linux/include/asm-arm/hardirq.h	Fri Aug  4 16:15:37 2000
+++ linux/include/asm-arm/hardirq.h	Wed Jul  4 14:56:44 2001
@@ -4,10 +4,9 @@
 #include <linux/config.h>
 #include <linux/threads.h>
 
-/* entry.S is sensitive to the offsets of these fields */
+/* softirq.h is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned int __softirq_pending;
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/mach/pci.h linux/include/asm-arm/mach/pci.h
--- v2.4.6/linux/include/asm-arm/mach/pci.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/mach/pci.h	Wed Jul  4 15:43:05 2001
@@ -7,36 +7,26 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#define MAX_NR_BUS	2
+struct hw_pci {
+	/* Initialise the hardware */
+	void		(*init)(void *);
+
+	/* Setup bus resources */
+	void		(*setup_resources)(struct resource **);
 
-struct arm_bus_sysdata {
-	/*
-	 * bitmask of features we can turn.
-	 * See PCI command register for more info.
-	 */
-	u16		features;
-	/*
-	 * Maximum devsel for this bus.
-	 */
-	u16		maxdevsel;
 	/*
-	 * The maximum latency that devices on this
-	 * bus can withstand.
+	 * This is the offset of PCI memory base registers
+	 * to physical memory.
 	 */
-	u8		max_lat;
-};
-
-struct arm_pci_sysdata {
-	struct arm_bus_sysdata bus[MAX_NR_BUS];
-};
+	unsigned long	mem_offset;
 
-struct hw_pci {
-	void		(*init)(struct arm_pci_sysdata *);
+	/* IRQ swizzle */
 	u8		(*swizzle)(struct pci_dev *dev, u8 *pin);
+
+	/* IRQ mapping */
 	int		(*map_irq)(struct pci_dev *dev, u8 slot, u8 pin);
 };
 
 extern u8 no_swizzle(struct pci_dev *dev, u8 *pin);
-
-void __init dc21285_init(struct arm_pci_sysdata *);
-void __init plx90x0_init(struct arm_pci_sysdata *);
+extern void __init dc21285_setup_resources(struct resource **resource);
+extern void __init dc21285_init(void *sysdata);
diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/softirq.h linux/include/asm-arm/softirq.h
--- v2.4.6/linux/include/asm-arm/softirq.h	Mon May 15 12:00:34 2000
+++ linux/include/asm-arm/softirq.h	Wed Jul  4 14:56:44 2001
@@ -4,12 +4,23 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define cpu_bh_disable(cpu)	do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
+#define __cpu_bh_enable(cpu) \
+		do { barrier(); local_bh_count(cpu)--; } while (0)
+#define cpu_bh_disable(cpu) \
+		do { local_bh_count(cpu)++; barrier(); } while (0)
 
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()	cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable()	__cpu_bh_enable(smp_processor_id())
+#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu))
+#define raise_softirq(nr)	__cpu_raise_softirq(smp_processor_id(), (nr))
 
 #define in_softirq()		(local_bh_count(smp_processor_id()) != 0)
+
+#define local_bh_enable()						\
+do {									\
+	unsigned int *ptr = &local_bh_count(smp_processor_id());	\
+	if (!--*ptr && ptr[-2])						\
+		__asm__("bl%? __do_softirq": : : "lr");/* out of line */\
+} while (0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/axisflashmap.h linux/include/asm-cris/axisflashmap.h
--- v2.4.6/linux/include/asm-cris/axisflashmap.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/axisflashmap.h	Wed Jul  4 11:50:39 2001
@@ -50,6 +50,7 @@
 };
 /* ended by an end marker: */
 #define PARTITIONTABLE_END_MARKER 0xFFFFFFFF
+#define PARTITIONTABLE_END_MARKER_SIZE 4
 
 /*#define PARTITION_TYPE_RESCUE 0x0000?*/  /* Not used, maybe it should? */
 #define PARTITION_TYPE_PARAM  0x0001 /* Hmm.. */
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/bitops.h linux/include/asm-cris/bitops.h
--- v2.4.6/linux/include/asm-cris/bitops.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/bitops.h	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,15 @@
-/* $Id: bitops.h,v 1.4 2001/02/28 04:26:11 hp Exp $ */
-/* all of these should probably be rewritten in assembler for speed. */
+/* asm/bitops.h for Linux/CRIS
+ *
+ * TODO: asm versions if speed is needed
+ *       set_bit, clear_bit and change_bit wastes cycles being only
+ *       macros into test_and_set_bit etc.
+ *       kernel-doc things (**) for macros are disabled
+ *
+ * All bit operations return 0 if the bit was cleared before the
+ * operation and != 0 if it was not.
+ *
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
 
 #ifndef _CRIS_BITOPS_H
 #define _CRIS_BITOPS_H
@@ -10,25 +20,72 @@
 #include <asm/system.h>
 
 /*
- * These have to be done with inline assembly: that way the bit-setting
- * is guaranteed to be atomic. All bit operations return 0 if the bit
- * was cleared before the operation and != 0 if it was not.
- *
- * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
- */
-
-/*
  * Some hacks to defeat gcc over-optimizations..
  */
 struct __dummy { unsigned long a[100]; };
 #define ADDR (*(struct __dummy *) addr)
 #define CONST_ADDR (*(const struct __dummy *) addr)
 
+/*
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+
 #define set_bit(nr, addr)    (void)test_and_set_bit(nr, addr)
+
+/*
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
+
 #define clear_bit(nr, addr)  (void)test_and_clear_bit(nr, addr)
+
+/*
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+
 #define change_bit(nr, addr) (void)test_and_change_bit(nr, addr)
 
-extern __inline__ int test_and_set_bit(int nr, void *addr)
+/*
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+
+#define __change_bit(nr, addr) (void)__test_and_change_bit(nr, addr)
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+
+static __inline__ int test_and_set_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -50,7 +107,16 @@
 #define smp_mb__before_clear_bit()      barrier()
 #define smp_mb__after_clear_bit()       barrier()
 
-extern __inline__ int test_and_clear_bit(int nr, void *addr)
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+
+static __inline__ int test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -66,7 +132,37 @@
 	return retval;
 }
 
-extern __inline__ int test_and_change_bit(int nr, void *addr)
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+
+static __inline__ int __test_and_clear_bit(int nr, void *addr)
+{
+	unsigned int mask, retval;
+	unsigned int *adr = (unsigned int *)addr;
+	
+	adr += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *adr) != 0;
+	*adr &= ~mask;
+	return retval;
+}
+/**
+ * test_and_change_bit - Change a bit and return its new value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+
+static __inline__ int test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -81,10 +177,30 @@
 	return retval;
 }
 
-/*
+/* WARNING: non atomic and it can be reordered! */
+
+static __inline__ int __test_and_change_bit(int nr, void *addr)
+{
+	unsigned int mask, retval;
+	unsigned int *adr = (unsigned int *)addr;
+
+	adr += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *adr) != 0;
+	*adr ^= mask;
+
+	return retval;
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ *
  * This routine doesn't need to be atomic.
  */
-extern __inline__ int test_bit(int nr, const void *addr)
+
+static __inline__ int test_bit(int nr, const void *addr)
 {
 	unsigned int mask;
 	unsigned int *adr = (unsigned int *)addr;
@@ -102,7 +218,7 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-extern __inline__ unsigned long ffz(unsigned long word)
+static __inline__ unsigned long ffz(unsigned long word)
 {
 	unsigned long result = 0;
 	
@@ -117,7 +233,7 @@
  * Find first one in word. Undefined if no one exists,
  * so code should check against 0UL first..
  */
-extern __inline__ unsigned long find_first_one(unsigned long word)
+static __inline__ unsigned long find_first_one(unsigned long word)
 {
 	unsigned long result = 0;
 	
@@ -128,7 +244,13 @@
 	return result;
 }
 
-extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
@@ -163,6 +285,15 @@
  found_middle:
 	return result + ffz(tmp);
 }
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
 
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/delay.h linux/include/asm-cris/delay.h
--- v2.4.6/linux/include/asm-cris/delay.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/delay.h	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.3 2001/02/23 13:47:33 bjornw Exp $ */
+/* $Id: delay.h,v 1.4 2001/05/31 06:40:53 markusl Exp $ */
 
 #ifndef _CRIS_DELAY_H
 #define _CRIS_DELAY_H
@@ -20,23 +20,17 @@
 
 extern __inline__ void __delay(int loops)
 {
-	/* need to be a great deal of nops, because Etrax shuts off IRQ's during a branch
-	   and we depend on the irq's to measure the time! */
-	
 	__asm__ __volatile__ (
-			      "move.d %0,r0\n"
+			      "move.d %0,r0\n\t"
 			      "1:\n\t"
-			      "nop\n\t"
-			      "nop\n\t"
-			      "nop\n\t"
-			      "nop\n\t"
-			      "nop\n\t"
-			      "nop\n\t"
+			      "cmpq 0,r0\n\t"
+			      "beq 2f\n\t"
 			      "nop\n\t"
 			      "subq 1,r0\n\t"
-			      "bne 1b\n\t"
+			      "ba 1b\n\t"
 			      "nop\n\t"
-			      : : "r" (loops) : "r0", "cc");
+			      "2:\n\t"
+			      : : "r" (loops) : "r0");
 }
 
 
@@ -55,13 +49,7 @@
 	__delay(usecs * loops_per_usec);
 }
 
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
-{
-	printk("muldiv called!\n");
-	return 0;
-}
-
-#endif /* defined(_ETRAX_DELAY_H) */
+#endif /* defined(_CRIS_DELAY_H) */
 
 
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/dma.h linux/include/asm-cris/dma.h
--- v2.4.6/linux/include/asm-cris/dma.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/dma.h	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $
+/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  */
 
@@ -13,6 +13,44 @@
 /* TODO: check nbr of channels on Etrax-100LX */
 
 #define MAX_DMA_CHANNELS	10
+
+/* dma0 and dma1 used for network (ethernet) */
+#define NETWORK_TX_DMA_NBR 0
+#define NETWORK_RX_DMA_NBR 1
+
+/* dma2 and dma3 shared by par0, scsi0, ser2 and ata */
+#define PAR0_TX_DMA_NBR 2
+#define PAR0_RX_DMA_NBR 3
+#define SCSI0_TX_DMA_NBR 2
+#define SCSI0_RX_DMA_NBR 3
+#define SER2_TX_DMA_NBR 2
+#define SER2_RX_DMA_NBR 3
+#define ATA_TX_DMA_NBR 2
+#define ATA_RX_DMA_NBR 3
+
+/* dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */
+#define PAR1_TX_DMA_NBR 4
+#define PAR1_RX_DMA_NBR 5
+#define SCSI1_TX_DMA_NBR 4
+#define SCSI1_RX_DMA_NBR 5
+#define SER3_TX_DMA_NBR 4
+#define SER3_RX_DMA_NBR 5
+#define EXTDMA0_TX_DMA_NBR 4
+#define EXTDMA0_RX_DMA_NBR 5
+
+/* dma6 and dma7 shared by ser0, extdma1 and mem2mem */
+#define SER0_TX_DMA_NBR 6
+#define SER0_RX_DMA_NBR 7
+#define EXTDMA1_TX_DMA_NBR 6
+#define EXTDMA1_RX_DMA_NBR 7
+#define MEM2MEM_TX_DMA_NBR 6
+#define MEM2MEM_RX_DMA_NBR 7
+
+/* dma8 and dma9 shared by ser1 and usb */
+#define SER1_TX_DMA_NBR 8
+#define SER1_RX_DMA_NBR 9
+#define USB_TX_DMA_NBR 8
+#define USB_RX_DMA_NBR 9
 
 /* These are in kernel/dma.c: */
 extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h
--- v2.4.6/linux/include/asm-cris/etraxgpio.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/etraxgpio.h	Wed Jul  4 11:50:39 2001
@@ -31,4 +31,8 @@
 /* LED ioctl extended */
 #define IO_LED_SETBIT 0xB
 #define IO_LED_CLRBIT 0xC
+
+/* SHUTDOWN ioctl */
+#define IO_SHUTDOWN   0xD
+#define IO_GET_PWR_BT 0xE
 #endif
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/io.h linux/include/asm-cris/io.h
--- v2.4.6/linux/include/asm-cris/io.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/io.h	Wed Jul  4 11:50:39 2001
@@ -128,12 +128,24 @@
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x))
 #define LED_DISK_READ(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x))     
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x))     
 #endif
 
 #ifdef CONFIG_ETRAX_CSP0_LEDS
+#define CONFIGURABLE_LEDS\
+        ((1 << CONFIG_ETRAX_LED1G ) | (1 << CONFIG_ETRAX_LED1R ) |\
+         (1 << CONFIG_ETRAX_LED2G ) | (1 << CONFIG_ETRAX_LED2R ) |\
+         (1 << CONFIG_ETRAX_LED3G ) | (1 << CONFIG_ETRAX_LED3R ) |\
+         (1 << CONFIG_ETRAX_LED4G ) | (1 << CONFIG_ETRAX_LED4R ) |\
+         (1 << CONFIG_ETRAX_LED5G ) | (1 << CONFIG_ETRAX_LED5R ) |\
+         (1 << CONFIG_ETRAX_LED6G ) | (1 << CONFIG_ETRAX_LED6R ) |\
+         (1 << CONFIG_ETRAX_LED7G ) | (1 << CONFIG_ETRAX_LED7R ) |\
+         (1 << CONFIG_ETRAX_LED8Y ) | (1 << CONFIG_ETRAX_LED9Y ) |\
+         (1 << CONFIG_ETRAX_LED10Y ) |(1 << CONFIG_ETRAX_LED11Y )|\
+         (1 << CONFIG_ETRAX_LED12R ))
+
 #define LED_NETWORK_SET_G(x) \
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x))
 #define LED_NETWORK_SET_R(x) \
@@ -146,10 +158,24 @@
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x))
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x))
-#define LED_BIT_SET(x) \
-         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1)
-#define LED_BIT_CLR(x) \
-          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0)        
+#define LED_BIT_SET(x)\
+        do{\
+                if((( 1 << x) & CONFIGURABLE_LEDS)  != 0)\
+                       REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1);\
+        }while(0)
+#define LED_BIT_CLR(x)\
+        do{\
+                if((( 1 << x) & CONFIGURABLE_LEDS)  != 0)\
+                       REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0);\
+        }while(0)
+#endif
+
+#
+#ifdef CONFIG_ETRAX_SOFT_SHUTDOWN
+#define SOFT_SHUTDOWN() \
+          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_SHUTDOWN_BIT, 1)
+#else
+#define SOFT_SHUTDOWN()
 #endif
 
 /*
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h
--- v2.4.6/linux/include/asm-cris/irq.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/irq.h	Wed Jul  4 11:50:39 2001
@@ -1,10 +1,11 @@
 /*
- * Interrupt handling assembler for Linux/CRIS
+ * Interrupt handling assembler and defines for Linux/CRIS
  *
  * Copyright (c) 2000 Axis Communications AB
  *
  * Authors:   Bjorn Wesen (bjornw@axis.com)
  *
+ * $Id: irq.h,v 1.11 2001/06/01 14:57:17 starvik Exp $
  */
 
 #ifndef _ASM_IRQ_H
@@ -20,6 +21,61 @@
 #include <asm/sv_addr_ag.h>
 
 #define NR_IRQS 32
+#define SOME_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, some)   /* 0 ? */
+#define NMI_IRQ_NBR         IO_BITNR(R_VECT_MASK_RD, nmi)    /* 1 */
+#define TIMER0_IRQ_NBR      IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */
+#define TIMER1_IRQ_NBR      IO_BITNR(R_VECT_MASK_RD, timer1) /* 3 */
+/* mio, ata, par0, scsi0 on 4 */
+/* par1, scsi1 on 5 */
+#define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */
+
+#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 8 */
+#define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */
+/* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */
+#define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0)
+#define EXTDMA1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma1)
+
+/* dma0-9 is irq 16..25 */
+/* 16,17: network */
+#define DMA0_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma0)
+#define DMA1_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma1)
+#define NETWORK_DMA_TX_IRQ_NBR DMA0_TX_IRQ_NBR
+#define NETWORK_DMA_RX_IRQ_NBR DMA1_RX_IRQ_NBR
+
+/* 18,19: dma2 and dma3 shared by par0, scsi0, ser2 and ata */
+#define DMA2_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma2)
+#define DMA3_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma3)
+#define SER2_DMA_TX_IRQ_NBR DMA2_TX_IRQ_NBR
+#define SER2_DMA_RX_IRQ_NBR DMA3_RX_IRQ_NBR
+
+/* 20,21: dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */
+#define DMA4_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma4)
+#define DMA5_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma5)
+#define SER3_DMA_TX_IRQ_NBR DMA4_TX_IRQ_NBR
+#define SER3_DMA_RX_IRQ_NBR DMA5_RX_IRQ_NBR
+
+/* 22,23: dma6 and dma7 shared by ser0, extdma1 and mem2mem */
+#define DMA6_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma6)
+#define DMA7_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma7)
+#define SER0_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR
+#define SER0_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR
+#define MEM2MEM_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR
+#define MEM2MEM_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR
+
+/* 24,25: dma8 and dma9 shared by ser1 and usb */
+#define DMA8_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma8)
+#define DMA9_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma9)
+#define SER1_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR
+#define SER1_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR
+#define USB_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR
+#define USB_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR
+
+/* usb: controller at irq 31 + uses DMA8 and DMA9 */
+#define USB_HC_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, usb)
+
+
+
+
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/mmu_context.h linux/include/asm-cris/mmu_context.h
--- v2.4.6/linux/include/asm-cris/mmu_context.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/mmu_context.h	Wed Jul  4 11:50:39 2001
@@ -9,6 +9,12 @@
 
 #define activate_mm(prev,next) switch_mm((prev),(next),NULL,smp_processor_id())
 
+/* current active pgd - this is similar to other processors pgd 
+ * registers like cr3 on the i386
+ */
+
+extern volatile pgd_t *current_pgd;   /* defined in arch/cris/mm/fault.c */
+
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h
--- v2.4.6/linux/include/asm-cris/ptrace.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/ptrace.h	Wed Jul  4 11:50:39 2001
@@ -22,8 +22,9 @@
 #define PT_MOF       16
 #define PT_DCCR      17
 #define PT_SRP       18
-#define PT_IRP       19
-#define PT_CSRINSTR  20    /* CPU Status record remnants - valid if frametype == busfault */
+#define PT_IRP       19    /* This is actually the debugged process' PC */
+#define PT_CSRINSTR  20    /* CPU Status record remnants -
+			      valid if frametype == busfault */
 #define PT_CSRADDR   21
 #define PT_CSRDATA   22
 #define PT_USP       23    /* special case - USP is not in the pt_regs */
@@ -31,12 +32,9 @@
 
 /* Frame types */
 
-#define CRIS_FRAME_NORMAL   0  /* normal frame without SBFS stacking */
-#define CRIS_FRAME_BUSFAULT 1  /* frame stacked using SBFS, need RBF return path */
-
-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-#define PTRACE_GETREGS            12
-#define PTRACE_SETREGS            13
+#define CRIS_FRAME_NORMAL   0 /* normal frame without SBFS stacking */
+#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return
+				 path */
 
 /* pt_regs not only specifices the format in the user-struct during
  * ptrace but is also the frame format used in the kernel prologue/epilogues 
@@ -47,10 +45,10 @@
 	unsigned long frametype;  /* type of stackframe */
 	unsigned long orig_r10;
 	/* pushed by movem r13, [sp] in SAVE_ALL, movem pushes backwards */
-	unsigned long r13; /* 8 */
-	unsigned long r12; /* 12 */
-	unsigned long r11; /* 16 */
-	unsigned long r10; /* 20 */
+	unsigned long r13;
+	unsigned long r12;
+	unsigned long r11;
+	unsigned long r10;
 	unsigned long r9;
 	unsigned long r8;
 	unsigned long r7;
@@ -64,20 +62,21 @@
 	unsigned long mof;
 	unsigned long dccr;
 	unsigned long srp;
-	unsigned long irp;
+	unsigned long irp; /* This is actually the debugged process' PC */
 	unsigned long csrinstr;
 	unsigned long csraddr;
 	unsigned long csrdata;
 };
 
-/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) when
-   doing a context-switch. it is used (apart from in resume) when a new thread is made 
-   and we need to make _resume (which is starting it for the first time) realise what
-   is going on. 
-
-   actually, the use is very close to the thread struct (TSS) in that both the switch_stack
-   and the TSS are used to keep thread stuff when switching in _resume.
-*/
+/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S)
+ * when doing a context-switch. it is used (apart from in resume) when a new
+ * thread is made and we need to make _resume (which is starting it for the
+ * first time) realise what is going on.
+ *
+ * Actually, the use is very close to the thread struct (TSS) in that both the
+ * switch_stack and the TSS are used to keep thread stuff when switching in
+ * _resume.
+ */
 
 struct switch_stack {
 	unsigned long r9;
@@ -94,6 +93,10 @@
 };
 
 #ifdef __KERNEL__
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+
 /* bit 8 is user-mode flag */
 #define user_mode(regs) ((regs)->dccr & 0x100)
 #define instruction_pointer(regs) ((regs)->irp)
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/semaphore.h linux/include/asm-cris/semaphore.h
--- v2.4.6/linux/include/asm-cris/semaphore.h	Tue Apr 17 17:19:30 2001
+++ linux/include/asm-cris/semaphore.h	Wed Jul  4 11:50:39 2001
@@ -1,4 +1,4 @@
-/* $Id: semaphore.h,v 1.2 2000/07/13 16:52:46 bjornw Exp $ */
+/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */
 
 /* On the i386 these are coded in asm, perhaps we should as well. Later.. */
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/svinto.h linux/include/asm-cris/svinto.h
--- v2.4.6/linux/include/asm-cris/svinto.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/svinto.h	Wed Jul  4 11:50:39 2001
@@ -33,14 +33,29 @@
 	unsigned long  next;                  /* 4-7 */
 	unsigned long  buf;                   /* 8-11 */
 	unsigned short hw_len;                /* 12-13 */
-	unsigned short status;                /* 14-15 */
+	unsigned char  status;                /* 14 */
+	unsigned char  fifo_len;              /* 15 */
 } etrax_dma_descr;
 
-#define RESET_DMA( n ) \
+
+/* Use this for constant numbers only */
+#define RESET_DMA_NUM( n ) \
   *R_DMA_CH##n##_CMD = IO_STATE( R_DMA_CH0_CMD, cmd, reset )
 
-#define WAIT_DMA( n ) \
+/* Use this for constant numbers or symbols, 
+ * having two macros makes it possible to use constant expressions. 
+ */
+#define RESET_DMA( n ) RESET_DMA_NUM( n )
+
+
+/* Use this for constant numbers only */
+#define WAIT_DMA_NUM( n ) \
   while( (*R_DMA_CH##n##_CMD & IO_MASK( R_DMA_CH0_CMD, cmd )) != \
          IO_STATE( R_DMA_CH0_CMD, cmd, hold ) )
+
+/* Use this for constant numbers or symbols 
+ * having two macros makes it possible to use constant expressions. 
+ */
+#define WAIT_DMA( n ) WAIT_DMA_NUM( n )
 
 #endif
diff -u --recursive --new-file v2.4.6/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.4.6/linux/include/asm-i386/processor.h	Fri May 25 18:01:26 2001
+++ linux/include/asm-i386/processor.h	Mon Jul  9 11:38:56 2001
@@ -222,6 +222,7 @@
 #define CX86_CCR4 0xe8
 #define CX86_CCR5 0xe9
 #define CX86_CCR6 0xea
+#define CX86_CCR7 0xeb
 #define CX86_DIR0 0xfe
 #define CX86_DIR1 0xff
 #define CX86_ARR_BASE 0xc4
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/atomic.h linux/include/asm-mips64/atomic.h
--- v2.4.6/linux/include/asm-mips64/atomic.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/atomic.h	Wed Jul  4 11:50:39 2001
@@ -21,7 +21,23 @@
 #ifdef __KERNEL__
 #define ATOMIC_INIT(i)    { (i) }
 
+/*
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 #define atomic_read(v)	((v)->counter)
+
+/*
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 #define atomic_set(v,i)	((v)->counter = (i))
 
 extern __inline__ void atomic_add(int i, volatile atomic_t * v)
@@ -37,6 +53,14 @@
 		: "Ir" (i), "m" (v->counter));
 }
 
+/*
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 extern __inline__ void atomic_sub(int i, volatile atomic_t * v)
 {
 	unsigned long temp;
@@ -94,11 +118,71 @@
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
 
+/*
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+
+/*
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ * atomic_inc_and_test is currently not implemented for mips64.
+ */
+
+/*
+ * atomic_dec_and_test - decrement by 1 and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
 
+/*
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 #define atomic_inc(v) atomic_add(1,(v))
+
+/*
+ * atomic_dec - decrement and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 #define atomic_dec(v) atomic_sub(1,(v))
+
+/*
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ *
+ * atomic_add_negative is currently not implemented for mips64.
+ */
+
 #endif /* defined(__KERNEL__) */
 
 #endif /* _ASM_ATOMIC_H */
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/bitops.h linux/include/asm-mips64/bitops.h
--- v2.4.6/linux/include/asm-mips64/bitops.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/bitops.h	Wed Jul  4 11:50:39 2001
@@ -21,16 +21,15 @@
 #include <asm/mipsregs.h>
 
 /*
- * clear_bit() doesn't provide any barrier for the compiler.
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
  */
-#define smp_mb__before_clear_bit()	barrier()
-#define smp_mb__after_clear_bit()	barrier()
-
-/*
- * These functions for MIPS ISA > 1 are interrupt and SMP proof and
- * interrupt friendly
- */
-
 extern __inline__ void
 set_bit(unsigned long nr, volatile void *addr)
 {
@@ -47,7 +46,15 @@
 		: "memory");
 }
 
-/* WARNING: non atomic and it can be reordered! */
+/*
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
 extern __inline__ void __set_bit(int nr, volatile void * addr)
 {
 	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
@@ -55,6 +62,16 @@
 	*m |= 1UL << (nr & 0x3f);
 }
 
+/*
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
 extern __inline__ void
 clear_bit(unsigned long nr, volatile void *addr)
 {
@@ -70,7 +87,18 @@
 		: "ir" (~(1UL << (nr & 0x3f))), "m" (*m));
 }
 
+#define smp_mb__before_clear_bit()	barrier()
+#define smp_mb__after_clear_bit()	barrier()
 
+/*
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
 extern __inline__ void
 change_bit(unsigned long nr, volatile void *addr)
 {
@@ -86,6 +114,30 @@
 		:"ir" (1UL << (nr & 0x3f)), "m" (*m));
 }
 
+/*
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+extern __inline__ void __change_bit(int nr, volatile void * addr)
+{
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+	*m ^= 1UL << (nr & 0x3f);
+}
+
+/*
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 extern __inline__ unsigned long
 test_and_set_bit(unsigned long nr, volatile void *addr)
 {
@@ -107,19 +159,37 @@
 	return res != 0;
 }
 
-extern __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+/*
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+extern __inline__ int
+__test_and_set_bit(int nr, volatile void * addr)
 {
-	int mask, retval;
-	volatile long *a = addr;
+	unsigned long mask, retval;
+	long *a = (unsigned long *) addr;
 
-	a += nr >> 6;
-	mask = 1 << (nr & 0x3f);
-	retval = (mask & *a) != 0;
+	a += (nr >> 6);
+	mask = 1UL << (nr & 0x3f);
+	retval = ((mask & *a) != 0);
 	*a |= mask;
 
 	return retval;
 }
 
+/*
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 extern __inline__ unsigned long
 test_and_clear_bit(unsigned long nr, volatile void *addr)
 {
@@ -142,19 +212,37 @@
 	return res != 0;
 }
 
-extern __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+/*
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+extern __inline__ int
+__test_and_clear_bit(int nr, volatile void * addr)
 {
-	int     mask, retval;
-	volatile long    *a = addr;
+	unsigned long mask, retval;
+	unsigned long *a = (unsigned long *) addr;
 
-	a += nr >> 6;
-	mask = 1 << (nr & 0x3f);
-	retval = (mask & *a) != 0;
+	a += (nr >> 6);
+	mask = 1UL << (nr & 0x3f);
+	retval = ((mask & *a) != 0);
 	*a &= ~mask;
 
 	return retval;
 }
 
+/*
+ * test_and_change_bit - Change a bit and return its new value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 extern __inline__ unsigned long
 test_and_change_bit(unsigned long nr, volatile void *addr)
 {
@@ -176,16 +264,51 @@
 	return res != 0;
 }
 
+/*
+ * __test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+extern __inline__ int
+__test_and_change_bit(int nr, volatile void * addr)
+{
+	unsigned long mask, retval;
+	unsigned long *a = (unsigned long *) addr;
+
+	a += (nr >> 6);
+	mask = 1UL << (nr & 0x3f);
+	retval = ((mask & *a) != 0);
+	*a ^= mask;
+
+	return retval;
+}
+/*
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
 extern __inline__ unsigned long
 test_bit(int nr, volatile void * addr)
 {
-	return 1UL & (((const long *) addr)[nr >> 6] >> (nr & 0x3f));
+	return 1UL & (((volatile unsigned long *) addr)[nr >> 6] >> (nr & 0x3f));
 }
 
 #ifndef __MIPSEB__
 
 /* Little endian versions. */
 
+/*
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
 extern __inline__ int
 find_first_zero_bit (void *addr, unsigned size)
 {
@@ -228,6 +351,12 @@
 	return res;
 }
 
+/*
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
 extern __inline__ int
 find_next_zero_bit (void * addr, int size, int offset)
 {
@@ -267,8 +396,10 @@
 #endif /* !(__MIPSEB__) */
 
 /*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
  */
 extern __inline__ unsigned long ffz(unsigned long word)
 {
@@ -288,8 +419,12 @@
 
 #ifdef __KERNEL__
 
+
 /*
- * ffs: find first bit set. This is defined the same way as
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from the above ffz (man ffs).
  */
@@ -297,8 +432,10 @@
 #define ffs(x) generic_ffs(x)
 
 /*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
  */
 
 #define hweight32(x) generic_hweight32(x)
@@ -310,11 +447,11 @@
 #ifdef __MIPSEB__
 
 /*
- * find_next_zero_bit() finds the first zero bit in a bit string of length
- * 'size' bits, starting the search at bit 'offset'. This is largely based
- * on Linus's ALPHA routines, which are pretty portable BTW.
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
  */
-
 extern __inline__ unsigned long
 find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/bootinfo.h linux/include/asm-mips64/bootinfo.h
--- v2.4.6/linux/include/asm-mips64/bootinfo.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/bootinfo.h	Wed Jul  4 11:50:39 2001
@@ -88,7 +88,7 @@
 /*
  * Valid machtype for group SGI
  */
-#define MACH_SGI_INDY		0	/* R4?K and R5K Indy workstaions */
+#define MACH_SGI_INDY		0	/* R4?K and R5K Indy workstations */
 #define MACH_SGI_CHALLENGE_S	1       /* The Challenge S server */
 #define MACH_SGI_INDIGO2	2	/* The Indigo2 system */
 #define MACH_SGI_IP27		3	/* Origin 200, Origin 2000, Onyx 2 */
@@ -144,6 +144,11 @@
 
 #define CL_SIZE      (80)
 
+#define BOOT_MEM_MAP_MAX        32
+#define BOOT_MEM_RAM            1
+#define BOOT_MEM_ROM_DATA       2
+#define BOOT_MEM_RESERVED       3
+
 #ifndef _LANGUAGE_ASSEMBLY
 
 /*
@@ -159,6 +164,24 @@
 extern unsigned long mips_machtype;
 extern unsigned long mips_machgroup;
 extern unsigned long mips_tlb_entries;
+
+/*
+ * A memory map that's built upon what was determined
+ * or specified on the command line.
+ */
+struct boot_mem_map {
+        int nr_map;
+        struct {
+                unsigned long addr;     /* start of memory segment */
+                unsigned long size;     /* size of memory segment */
+                long type;              /* type of memory segment */
+        } map[BOOT_MEM_MAP_MAX];
+};
+
+extern struct boot_mem_map boot_mem_map;
+
+extern void add_memory_region(unsigned long start, unsigned long size,
+                              long type);
 
 #endif /* _LANGUAGE_ASSEMBLY */
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/cache.h linux/include/asm-mips64/cache.h
--- v2.4.6/linux/include/asm-mips64/cache.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/cache.h	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: cache.h,v 1.3 2000/02/04 07:40:53 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -11,7 +10,6 @@
 #define _ASM_CACHE_H
 
 /* bytes per L1 cache line */
-#define L1_CACHE_BYTES		32	/* A guess */
-#define SMP_CACHE_BYTES		L1_CACHE_BYTES
+#define L1_CACHE_BYTES		(1 << CONFIG_L1_CACHE_SHIFT)
 
 #endif /* _ASM_CACHE_H */
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/checksum.h linux/include/asm-mips64/checksum.h
--- v2.4.6/linux/include/asm-mips64/checksum.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/checksum.h	Wed Jul  4 11:50:39 2001
@@ -1,15 +1,17 @@
-/* $Id: checksum.h,v 1.6 2000/02/18 22:06:19 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle
  * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2001 Thiemo Seufer.
  */
 #ifndef _ASM_CHECKSUM_H
 #define _ASM_CHECKSUM_H
 
+#include <asm/uaccess.h>
+
 /*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
@@ -22,7 +24,7 @@
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
 
 /*
  * this is a new version of the above that records errors it finds in *errp,
@@ -41,9 +43,9 @@
  * Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-extern inline unsigned int
-csum_and_copy_to_user (const char *src, char *dst,
-                       int len, int sum, int *err_ptr)
+extern inline unsigned int csum_and_copy_to_user (const char *src, char *dst,
+						  int len, int sum,
+						  int *err_ptr)
 {
 	sum = csum_partial(src, len, sum);
 
@@ -62,23 +64,23 @@
  * this is obsolete and will go away.
  */
 #define csum_partial_copy_fromuser csum_partial_copy
-unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum);
-  
+unsigned int csum_partial_copy(const char *src, char *dst, int len,
+			       unsigned int sum);
+
 /*
  *	Fold a partial checksum without adding pseudo headers
  */
-static inline unsigned short int
-csum_fold(unsigned int sum)
+static inline unsigned short int csum_fold(unsigned int sum)
 {
-	__asm__("
-	.set	noat            
-	sll	$1, %0, 16
-	addu	%0, $1
-	sltu	$1, %0, $1
-	srl	%0, %0, 16
-	addu	%0, $1
-	xori	%0, 0xffff
-	.set	at"
+	__asm__(
+	".set\tnoat\t\t\t# csum_fold\n\t"
+	"sll\t$1,%0,16\n\t"
+	"addu\t%0,$1\n\t"
+	"sltu\t$1,%0,$1\n\t"
+	"srl\t%0,%0,16\n\t"
+	"addu\t%0,$1\n\t"
+	"xori\t%0,0xffff\n\t"
+	".set\tat"
 	: "=r" (sum)
 	: "0" (sum)
 	: "$1");
@@ -93,8 +95,8 @@
  *	By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
  *	Arnt Gulbrandsen.
  */
-static inline unsigned short
-ip_fast_csum(unsigned char * iph, unsigned int ihl)
+static inline unsigned short ip_fast_csum(unsigned char *iph,
+					  unsigned int ihl)
 {
 	unsigned int sum;
 	unsigned long dummy;
@@ -103,36 +105,35 @@
 	 * This is for 32-bit processors ...  but works just fine for 64-bit
 	 * processors for now ...  XXX
 	 */
-	__asm__ __volatile__("
-	.set	noreorder
-	.set	noat
-	lw	%0, (%1)
-	subu	%2, 4
-	dsll	%2, 2
-
-	lw	%3, 4(%1)
-	daddu	%2, %1
-	addu	%0, %3
-	sltu	$1, %0, %3
-	lw	%3, 8(%1)
-	addu	%0, $1
-	addu	%0, %3
-	sltu	$1, %0, %3
-	lw	%3, 12(%1)
-	addu	%0, $1
-	addu	%0, %3
-	sltu	$1, %0, %3
-	addu	%0, $1
-
-1:	lw	%3, 16(%1)
-	daddiu	%1, 4
-	addu	%0, %3
-	sltu	$1, %0, %3
-	bne	%2, %1, 1b
-	 addu	%0, $1
+	__asm__ __volatile__(
+	".set\tnoreorder\t\t\t# ip_fast_csum\n\t"
+	".set\tnoat\n\t"
+	"lw\t%0, (%1)\n\t"
+	"subu\t%2, 4\n\t"
+	"dsll\t%2, 2\n\t"
+	"lw\t%3, 4(%1)\n\t"
+	"daddu\t%2, %1\n\t"
+	"addu\t%0, %3\n\t"
+	"sltu\t$1, %0, %3\n\t"
+	"lw\t%3, 8(%1)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %3\n\t"
+	"sltu\t$1, %0, %3\n\t"
+	"lw\t%3, 12(%1)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %3\n\t"
+	"sltu\t$1, %0, %3\n\t"
+	"addu\t%0, $1\n"
+
+	"1:\tlw\t%3, 16(%1)\n\t"
+	"daddiu\t%1, 4\n"
+	"addu\t%0, %3\n\t"
+	"sltu\t$1, %0, %3\n\t"
+	"bne\t%2, %1, 1b\n\t"
+	" addu\t%0, $1\n"
 
-2:	.set	at
-	.set	reorder"
+	"2:\t.set\tat\n\t"
+	".set\treorder"
 	: "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (dummy)
 	: "1" (iph), "2" (ihl)
 	: "$1");
@@ -144,26 +145,29 @@
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
  */
-static inline unsigned long
-csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
-                   unsigned short len, unsigned short proto, unsigned int sum)
-{
-    __asm__("
-	.set	noat
-	daddu	%0, %2
-	daddu	%0, %3
-	daddu	%0, %4
-	dsll32	$1, %0, 0
-	daddu	%0, $1		# never results in an overflow
-	dsrl32	%0, %0, 0
-	.set	at"
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+					       unsigned long daddr,
+					       unsigned short len,
+					       unsigned short proto,
+					       unsigned int sum)
+{
+	__asm__(
+	".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t"
+	"daddu\t%0, %2\n\t"
+	"daddu\t%0, %3\n\t"
+	"daddu\t%0, %4\n\t"
+	"dsll32\t$1, %0, 0\n\t"
+	"daddu\t%0, $1\n\t"
+	"dsrl32\t%0, %0, 0\n\t"
+	".set\tat"
 	: "=r" (sum)
-	: "0" (sum), "r"(saddr), "r" (daddr),
+	: "0" (daddr), "r"(saddr),
 #ifdef __MIPSEL__
-	    "r" ((ntohs(len)<<16)+proto*256)
+	  "r" ((ntohs(len)<<16)+proto*256),
 #else
-	    "r" (((proto)<<16)+len)
+	  "r" (((proto)<<16)+len),
 #endif
+	  "r" (sum)
 	: "$1");
 
 	return sum;
@@ -173,82 +177,85 @@
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
  */
-static inline unsigned short int
-csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
-                  unsigned short proto, unsigned int sum)
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+						   unsigned long daddr,
+						   unsigned short len,
+						   unsigned short proto,
+						   unsigned int sum)
 {
-	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 }
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
-static inline unsigned short
-ip_compute_csum(unsigned char * buff, int len)
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
 {
 	return csum_fold(csum_partial(buff, len, 0));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
-static inline unsigned short int
-csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u32 len,
-                unsigned short proto, unsigned int sum) 
-{
-	__asm__("
-		.set	noreorder
-		.set	noat
-		addu	%0, %5		# proto (long in network byte order)
-		sltu	$1, %0, %5
-		addu	%0, $1
-
-		addu	%0, %6		# csum
-		sltu	$1, %0, %6
-		lw	%1, 0(%2)	# four words source address
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 4(%2)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 8(%2)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 12(%2)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 0(%3)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 4(%3)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 8(%3)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-
-		lw	%1, 12(%3)
-		addu	%0, $1
-		addu	%0, %1
-		sltu	$1, %0, $1
-		.set	noat
-		.set	noreorder"
-		: "=r" (sum), "=r" (proto)
-		: "r" (saddr), "r" (daddr),
-		  "0" (htonl(len)), "1" (htonl(proto)), "r"(sum)
-		: "$1");
+static inline unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+						 struct in6_addr *daddr,
+						 __u32 len,
+						 unsigned short proto,
+						 unsigned int sum) 
+{
+	__asm__(
+	".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t"
+	".set\tnoat\n\t"
+	"addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t"
+	"sltu\t$1, %0, %5\n\t"
+	"addu\t%0, $1\n\t"
+
+	"addu\t%0, %6\t\t\t# csum\n\t"
+	"sltu\t$1, %0, %6\n\t"
+	"lw\t%1, 0(%2)\t\t\t# four words source address\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 4(%2)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 8(%2)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 12(%2)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 0(%3)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 4(%3)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 8(%3)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+
+	"lw\t%1, 12(%3)\n\t"
+	"addu\t%0, $1\n\t"
+	"addu\t%0, %1\n\t"
+	"sltu\t$1, %0, $1\n\t"
+	".set\tnoat\n\t"
+	".set\tnoreorder"
+	: "=r" (sum), "=r" (proto)
+	: "r" (saddr), "r" (daddr),
+	  "0" (htonl(len)), "1" (htonl(proto)), "r" (sum)
+	: "$1");
 
 	return csum_fold(sum);
 }
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/cpu.h linux/include/asm-mips64/cpu.h
--- v2.4.6/linux/include/asm-mips64/cpu.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/cpu.h	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: cpu.h,v 1.1 1999/10/19 20:51:53 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -18,17 +17,18 @@
  * be examined.
  */
 #define PRID_IMP_R2000    0x0100
-#define PRID_IMP_R3000    0x0200
-#define PRID_IMP_R6000    0x0300
+#define PRID_IMP_R3000    0x0200	/* Same as R2000A  */
+#define PRID_IMP_R6000    0x0300	/* Same as R3000A  */
 #define PRID_IMP_R4000    0x0400
 #define PRID_IMP_R6000A   0x0600
 #define PRID_IMP_R10000   0x0900
 #define PRID_IMP_R4300    0x0b00
+#define PRID_IMP_R12000   0x0e00
 #define PRID_IMP_R8000    0x1000
 #define PRID_IMP_R4600    0x2000
 #define PRID_IMP_R4700    0x2100
 #define PRID_IMP_R4640    0x2200
-#define PRID_IMP_R4650    0x2200		/* Same as R4640 */
+#define PRID_IMP_R4650    0x2200	/* Same as R4640 */
 #define PRID_IMP_R5000    0x2300
 #define PRID_IMP_SONIC    0x2400
 #define PRID_IMP_MAGIC    0x2500
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/delay.h linux/include/asm-mips64/delay.h
--- v2.4.6/linux/include/asm-mips64/delay.h	Sun Feb  4 21:48:46 2001
+++ linux/include/asm-mips64/delay.h	Wed Jul  4 11:50:39 2001
@@ -12,7 +12,7 @@
 
 #include <linux/config.h>
 
-extern unsigned long loops_per_sec;
+extern unsigned long loops_per_jiffy;
 
 extern __inline__ void
 __delay(unsigned long loops)
@@ -36,21 +36,21 @@
  * first constant multiplications gets optimized away if the delay is
  * a constant)
  */
-extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lpj)
 {
 	unsigned long lo;
 
-	usecs *= 0x000010c6f7a0b5edUL;		/* 2**64 / 1000000 */
+	usecs *= 0x00068db8bac710cbUL;		/* 2**64 / (1000000 / HZ) */
 	__asm__("dmultu\t%2,%3"
 		:"=h" (usecs), "=l" (lo)
-		:"r" (usecs),"r" (lps));
+		:"r" (usecs),"r" (lpj));
 	__delay(usecs);
 }
 
 #ifdef CONFIG_SMP
 #define __udelay_val cpu_data[smp_processor_id()].udelay_val
 #else
-#define __udelay_val loops_per_sec
+#define __udelay_val loops_per_jiffy
 #endif
 
 #define udelay(usecs) __udelay((usecs),__udelay_val)
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/elf.h linux/include/asm-mips64/elf.h
--- v2.4.6/linux/include/asm-mips64/elf.h	Thu Jul 27 18:36:54 2000
+++ linux/include/asm-mips64/elf.h	Wed Jul  4 11:50:39 2001
@@ -29,8 +29,7 @@
 	int __res = 1;							\
 	struct elfhdr *__h = (hdr);					\
 									\
-	if ((__h->e_machine != EM_MIPS) &&				\
-	    (__h->e_machine != EM_MIPS_RS4_BE))				\
+	if (__h->e_machine != EM_MIPS)					\
 		__res = 0;						\
 	if (sizeof(elf_caddr_t) == 8 &&					\
 	    __h->e_ident[EI_CLASS] == ELFCLASS32)			\
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/gcc/sgidefs.h linux/include/asm-mips64/gcc/sgidefs.h
--- v2.4.6/linux/include/asm-mips64/gcc/sgidefs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips64/gcc/sgidefs.h	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,17 @@
+/*
+ * include/sgidefs.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996 by Ralf Baechle
+ *
+ * This file is here to satisfy GCC's expectations.
+ */
+#ifndef __SGIDEFS_H
+#define __SGIDEFS_H
+
+#include <asm/sgidefs.h>
+
+#endif /* __SGIDEFS_H */
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/hdreg.h linux/include/asm-mips64/hdreg.h
--- v2.4.6/linux/include/asm-mips64/hdreg.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/hdreg.h	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -7,12 +6,13 @@
  *  This file contains the MIPS architecture specific IDE code.
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ *  Copyright (C) 2001 Ralf Baechle
  */
 
 #ifndef _ASM_HDREG_H
 #define _ASM_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* _ASM_HDREG_H */
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/ide.h linux/include/asm-mips64/ide.h
--- v2.4.6/linux/include/asm-mips64/ide.h	Sun Jul  9 22:18:15 2000
+++ linux/include/asm-mips64/ide.h	Wed Jul  4 11:50:39 2001
@@ -8,10 +8,6 @@
  * Copyright (C) 1994-1996  Linus Torvalds & authors
  */
 
-/*
- *  This file contains the MIPS architecture specific IDE code.
- */
-
 #ifndef __ASM_IDE_H
 #define __ASM_IDE_H
 
@@ -128,6 +124,52 @@
 {
 	ide_ops->ide_release_region(from, extent);
 }
+
+
+#if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
+
+#ifdef insl
+#undef insl
+#endif
+#ifdef outsl
+#undef outsl
+#endif
+#ifdef insw
+#undef insw
+#endif
+#ifdef outsw
+#undef outsw
+#endif
+
+#define insw(p,a,c)							\
+do {									\
+	unsigned short *ptr = (unsigned short *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		*ptr++ = inw(p);					\
+} while (0)
+#define insl(p,a,c)							\
+do {									\
+	unsigned long *ptr = (unsigned long *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		*ptr++ = inl(p);					\
+} while (0)
+#define outsw(p,a,c)							\
+do {									\
+	unsigned short *ptr = (unsigned short *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		outw(*ptr++, (p));					\
+} while (0)
+#define outsl(p,a,c) {							\
+	unsigned long *ptr = (unsigned long *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		outl(*ptr++, (p));					\
+} while (0)
+
+#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
 
 /*
  * The following are not needed for the non-m68k ports
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/io.h linux/include/asm-mips64/io.h
--- v2.4.6/linux/include/asm-mips64/io.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/io.h	Wed Jul  4 11:50:39 2001
@@ -185,7 +185,7 @@
 	".set\tnoreorder\n\t" \
 	".set\tnoat\n" \
 	"1:\tl" #m "\t$1, %4(%5)\n\t" \
-	"dsubiu\t%1, 1\n\t" \
+	"dsubu\t%1, 1\n\t" \
 	"s" #m "\t$1,(%0)\n\t" \
 	"bnez\t%1, 1b\n\t" \
 	"daddiu\t%0, %6\n\t" \
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/ioctl.h linux/include/asm-mips64/ioctl.h
--- v2.4.6/linux/include/asm-mips64/ioctl.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/ioctl.h	Wed Jul  4 11:50:39 2001
@@ -1,10 +1,9 @@
-/* $Id$
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996, 1999 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1999, 2001 by Ralf Baechle
  */
 #ifndef _ASM_IOCTL_H
 #define _ASM_IOCTL_H
@@ -39,11 +38,6 @@
 #define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)
 
 /*
- * We to additionally limit parameters to a maximum 255 bytes.
- */
-#define _IOC_SLMASK	0xff
-
-/*
  * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit.
  * And this turns out useful to catch old ioctl numbers in header
  * files for us.
@@ -64,7 +58,7 @@
 	(((dir)  << _IOC_DIRSHIFT) | \
 	 ((type) << _IOC_TYPESHIFT) | \
 	 ((nr)   << _IOC_NRSHIFT) | \
-	 (((size) & _IOC_SLMASK) << _IOC_SIZESHIFT))
+	 ((size) << _IOC_SIZESHIFT))
 
 /* used to create numbers */
 #define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/irq.h linux/include/asm-mips64/irq.h
--- v2.4.6/linux/include/asm-mips64/irq.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/irq.h	Wed Jul  4 11:50:39 2001
@@ -6,15 +6,32 @@
  * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
  * Copyright (C) 1995, 96, 97, 98, 1999, 2000 by Ralf Baechle
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 Kanoj Sarcar
  */
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
 #include <linux/config.h>
+#include <asm/sn/arch.h>
 
 #define NR_IRQS 256
 
-#define TIMER_IRQ 0
+/*
+ * Number of levels in INT_PEND0. Can be set to 128 if we also
+ * consider INT_PEND1.
+ */
+#define PERNODE_LEVELS	64
+
+extern int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS];
+
+/*
+ * we need to map irq's up to at least bit 7 of the INT_MASK0_A register
+ * since bits 0-6 are pre-allocated for other purposes.
+ */
+#define LEAST_LEVEL	7
+#define FAST_IRQ_TO_LEVEL(i)	((i) + LEAST_LEVEL)
+#define LEVEL_TO_IRQ(c, l) \
+			(node_level_to_irq[CPUID_TO_COMPACT_NODEID(c)][(l)])
 
 #ifdef CONFIG_I8259
 static inline int irq_cannonicalize(int irq)
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/mipsregs.h linux/include/asm-mips64/mipsregs.h
--- v2.4.6/linux/include/asm-mips64/mipsregs.h	Fri Apr 13 20:26:07 2001
+++ linux/include/asm-mips64/mipsregs.h	Wed Jul  4 11:50:39 2001
@@ -246,7 +246,7 @@
 #define  CAUSEF_BD		(1   << 31)
 
 /*
- * Bits in the coprozessor 0 config register.
+ * Bits in the coprocessor 0 config register.
  */
 #define CONF_CM_CACHABLE_NO_WA		0
 #define CONF_CM_CACHABLE_WA		1
@@ -265,7 +265,7 @@
  * R10000 performance counter definitions.
  *
  * FIXME: The R10000 performance counter opens a nice way to implement CPU
- *        time accounting with a precission of one cycle.  I don't have
+ *        time accounting with a precision of one cycle.  I don't have
  *        R10000 silicon but just a manual, so ...
  */
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/pci.h linux/include/asm-mips64/pci.h
--- v2.4.6/linux/include/asm-mips64/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-mips64/pci.h	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: pci.h,v 1.4 2000/02/24 00:13:20 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -196,8 +195,21 @@
 #endif
 }
 
-/* Return the index of the PCI controller for device PDEV. */
-#define pci_controller_num(PDEV)	(0)
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	/*
+	 * we fall back to GFP_DMA when the mask isn't all 1s,
+	 * so we can't guarantee allocations that must be
+	 * within a tighter range than GFP_DMA..
+	 */
+	if (mask < 0x00ffffff)
+		return 0;
+
+	return 1;
+}
+
+/* Return the index of the PCI controller for device. */
+#define pci_controller_num(pdev)	(0)
 
 /*
  * These macros should be used after a pci_map_sg call has been done
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/pgalloc.h linux/include/asm-mips64/pgalloc.h
--- v2.4.6/linux/include/asm-mips64/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-mips64/pgalloc.h	Wed Jul  4 11:50:39 2001
@@ -3,8 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994 - 2000 by Ralf Baechle at alii
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1994 - 2001 by Ralf Baechle at alii
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_PGALLOC_H
 #define _ASM_PGALLOC_H
@@ -49,9 +49,7 @@
 
 
 /*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
+ * Allocate and free page tables.
  */
 
 #define pgd_quicklist (current_cpu_data.pgd_quick)
@@ -59,6 +57,9 @@
 #define pte_quicklist (current_cpu_data.pte_quick)
 #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
 
+#define pmd_populate(mm, pmd, pte)	pmd_set(pmd, pte)
+#define pgd_populate(mm, pgd, pmd)	pgd_set(pgd, pmd)
+
 extern pgd_t *get_pgd_slow(void);
 
 extern inline pgd_t *get_pgd_fast(void)
@@ -88,8 +89,29 @@
 	free_pages((unsigned long)pgd, 1);
 }
 
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte)
+		clear_page(pte);
+	return pte;
+}
+
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+{
+	unsigned long *ret;
+
+	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
+
 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
 
 extern inline pte_t *get_pte_fast(void)
 {
@@ -115,8 +137,29 @@
 	free_pages((unsigned long)pte, 0);
 }
 
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pmd_t *pmd;
+
+	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1);
+	if (pmd)
+		pmd_init((unsigned long)pmd, (unsigned long)invalid_pte_table);
+	return pmd;
+}
+
+static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+{
+	unsigned long *ret;
+
+	if ((ret = (unsigned long *)pmd_quicklist) != NULL) {
+		pmd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	}
+	return (pmd_t *)ret;
+}
+
 extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_preadjusted);
-extern pmd_t *get_pmd_kernel_slow(pgd_t *pgd, unsigned long address_preadjusted);
 
 extern inline pmd_t *get_pmd_fast(void)
 {
@@ -144,61 +187,13 @@
 	free_pages((unsigned long)pmd, 1);
 }
 
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pte_kernel(pmd_t *pmd);
-extern void __bad_pmd(pgd_t *pgd);
-
 #define pte_free(pte)           free_pte_fast(pte)
 #define pmd_free(pte)           free_pmd_fast(pte)
 #define pgd_free(pgd)           free_pgd_fast(pgd)
 #define pgd_alloc(mm)           get_pgd_fast()
 
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
-	if (pmd_none(*pmd)) {
-		pte_t *page = get_pte_fast();
-		if (page) {
-			pmd_val(*pmd) = (unsigned long) page;
-			return page + address;
-		}
-		return get_pte_slow(pmd, address);
-	}
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-extern inline pmd_t *pmd_alloc(pgd_t * pgd, unsigned long address)
-{
-	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *page = get_pmd_fast();
-
-		if (!page)
-			return get_pmd_slow(pgd, address);
-		pgd_set(pgd, page);
-		return page + address;
-	}
-	if (pgd_bad(*pgd)) {
-		__bad_pmd(pgd);
-		return NULL;
-	}
-	return (pmd_t *) pgd_page(*pgd) + address;
-}
-
 extern pte_t kptbl[(PAGE_SIZE<<KPTBL_PAGE_ORDER)/sizeof(pte_t)];
 extern pmd_t kpmdtbl[PTRS_PER_PMD];
-
-#define pmd_alloc_kernel(d,a)	(pmd_t *)kpmdtbl
-
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
-{
-	return (kptbl + (address >> PAGE_SHIFT));
-}
 
 extern int do_check_pgt_cache(int, int);
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/pgtable.h linux/include/asm-mips64/pgtable.h
--- v2.4.6/linux/include/asm-mips64/pgtable.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/pgtable.h	Wed Jul  4 11:50:39 2001
@@ -3,8 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994 - 2000 by Ralf Baechle at alii
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1994 - 2001 by Ralf Baechle at alii
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_PGTABLE_H
 #define _ASM_PGTABLE_H
@@ -177,15 +177,25 @@
 
 #define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK)
 
-#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_COW)
+#ifdef CONFIG_MIPS_UNCACHED
+#define PAGE_CACHABLE_DEFAULT _CACHE_UNCACHED
+#else /* ! UNCACHED */
+#ifdef CONFIG_SGI_IP22
+#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_NONCOHERENT
+#else /* ! IP22 */
+#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_COW
+#endif /* IP22 */
+#endif /* UNCACHED */
+
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | PAGE_CACHABLE_DEFAULT)
 #define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
-			_CACHE_CACHABLE_COW)
+			PAGE_CACHABLE_DEFAULT)
 #define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_READ | \
-			_CACHE_CACHABLE_COW)
+			PAGE_CACHABLE_DEFAULT)
 #define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_READ | \
-			_CACHE_CACHABLE_COW)
+			PAGE_CACHABLE_DEFAULT)
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
-			_CACHE_CACHABLE_COW)
+			PAGE_CACHABLE_DEFAULT)
 #define PAGE_USERIO     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
 			_CACHE_UNCACHED)
 #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
@@ -224,22 +234,13 @@
 	printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e))
 
 /*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern pte_t __bad_page(void);
-extern pte_t *__bad_pagetable(void);
-extern pmd_t *__bad_pmd_table(void);
 
 extern unsigned long empty_zero_page;
 extern unsigned long zero_page_mask;
 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PMDTABLE __bad_pmd_table()
-#define BAD_PAGE __bad_page()
 #define ZERO_PAGE(vaddr) \
 	(virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask)))
 
@@ -297,7 +298,8 @@
 	return pte_val(pte) & _PAGE_PRESENT;
 }
 
-/* Certain architectures need to do special things when pte's
+/*
+ * Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
@@ -312,6 +314,13 @@
 }
 
 /*
+ * (pmds are folded into pgds so this doesnt get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
+/*
  * Empty pmd entries point to the invalid_pte_table.
  */
 extern inline int pmd_none(pmd_t pmd)
@@ -321,7 +330,12 @@
 
 extern inline int pmd_bad(pmd_t pmd)
 {
-	return pmd_val(pmd) == (unsigned long) empty_bad_page_table;
+	return pmd_val(pmd) &~ PAGE_MASK;
+}
+
+extern inline int pmd_present(pmd_t pmd)
+{
+	return pmd_val(pmd) != (unsigned long) invalid_pte_table;
 }
 
 extern inline void pmd_clear(pmd_t *pmdp)
@@ -339,7 +353,12 @@
 
 extern inline int pgd_bad(pgd_t pgd)
 {
-	return pgd_val(pgd) == (unsigned long) empty_bad_pmd_table;
+	return pgd_val(pgd) &~ PAGE_MASK;
+}
+
+extern inline int pgd_present(pgd_t pgd)
+{
+	return pgd_val(pgd) != (unsigned long) invalid_pmd_table;
 }
 
 extern inline void pgd_clear(pgd_t *pgdp)
@@ -350,7 +369,6 @@
 /*
  * Permanent address of a page.  On MIPS64 we never have highmem, so this
  * is simple.
- * called on a highmem page.
  */
 #define page_address(page)	((page)->virtual)
 #ifndef CONFIG_DISCONTIGMEM
@@ -761,7 +779,7 @@
 
 	__asm__ __volatile__(
 		".set noreorder\n\t"
-		"mfc0 %0, $4\n\t"
+		"dmfc0 %0, $4\n\t"
 		".set reorder"
 		: "=r" (val));
 
@@ -772,7 +790,7 @@
 {
 	__asm__ __volatile__(
 		".set noreorder\n\t"
-		"mtc0 %0, $4\n\t"
+		"dmtc0 %0, $4\n\t"
 		".set reorder"
 		: : "r" (val));
 }
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/processor.h linux/include/asm-mips64/processor.h
--- v2.4.6/linux/include/asm-mips64/processor.h	Sat Dec 30 09:35:40 2000
+++ linux/include/asm-mips64/processor.h	Wed Jul  4 11:50:39 2001
@@ -26,7 +26,7 @@
 ({									\
 	void *_a;							\
 									\
-	__asm__ ("jal\t1f, 1f\n\t"					\
+	__asm__ ("jal\t1f, %0\n\t"					\
 		"1:"							\
 		: "=r" (_a));						\
 									\
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/rrm.h linux/include/asm-mips64/rrm.h
--- v2.4.6/linux/include/asm-mips64/rrm.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips64/rrm.h	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,88 @@
+/*
+ * SGI Rendering Resource Manager API (?).
+ *
+ * written by Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Ok, even if SGI choosed to do mmap trough ioctls, their
+ * kernel support for virtualizing the graphics card is nice.
+ *
+ * We should be able to make graphic applications on Linux
+ * fly.
+ *
+ * This header file should be included from GNU libc as well.
+ */
+
+
+/* Why like this you say?  Well, gdb can print enums */
+#define RRM_BASE 1000
+#define RRM_CMD_LIMIT (RRM_BASE + 100)
+
+enum {
+	RRM_OPENRN = RRM_BASE,	/* open rendering node */
+	RRM_CLOSERN,
+	RRM_BINDPROCTORN,	/* set current rendering region for node */
+	RRM_BINDRNTOCLIP,
+	RRM_UNBINDRNFROMCLIP,
+	RRM_SWAPBUF,
+	RRM_SETSWAPINTERVAL,
+	RRM_WAITFORRETRACE,
+	RRM_SETDISPLAYMODE,
+	RRM_MESSAGE,
+	RRM_INVALIDATERN,
+	RRM_VALIDATECLIP,
+	RRM_VALIDATESWAPBUF,
+	RRM_SWAPGROUP,
+	RRM_SWAPUNGROUP,
+	RRM_VALIDATEMESSAGE,
+	RRM_GETDISPLAYMODES,
+	RRM_LOADDISPLAYMODE,
+	RRM_CUSHIONBUFFER,
+	RRM_SWAPREADY,
+	RRM_MGR_SWAPBUF,
+	RRM_SETVSYNC,
+	RRM_GETVSYNC,
+	RRM_WAITVSYNC,
+	RRM_BINDRNTOREADANDCLIP,
+	RRM_MAPCLIPTOSWPBUFID
+};
+
+/* Parameters for the above ioctls
+ *
+ * All of the ioctls take as their first argument the rendering node id.
+ *
+ */
+
+/*
+ * RRM_OPENRN:
+ *
+ * This is called by the IRIX X server with:
+ * rnid = 0xffffffff rmask = 0
+ *
+ * Returns a number like this: 0x10001.
+ * If you run the X server over and over, you get a value
+ * that is of the form (n * 0x10000) + 1.
+ *
+ * The return value seems to be the RNID.
+ */
+struct RRM_OpenRN {
+	int      rnid;
+	unsigned int rmask;
+};
+
+struct RRM_CloseRN {
+	int rnid;
+};
+
+/*
+ * RRM_BINDPROCTORN:
+ *
+ * Return value when the X server calls it: 0
+ */ 
+struct RRM_BindProcToRN {
+	int      rnid;
+};
+
+#ifdef __KERNEL__
+int rrm_command (unsigned int cmd, void *arg);
+int rrm_close (struct inode *inode, struct file *file);
+#endif
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/semaphore-helper.h linux/include/asm-mips64/semaphore-helper.h
--- v2.4.6/linux/include/asm-mips64/semaphore-helper.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/semaphore-helper.h	Wed Jul  4 11:50:39 2001
@@ -3,8 +3,8 @@
  *
  * (C) Copyright 1996 Linus Torvalds
  * (C) Copyright 1999 Andrea Arcangeli
- * (C) Copyright 1999 Ralf Baechle
- * (C) Copyright 1999 Silicon Graphics, Inc.
+ * (C) Copyright 1999, 2001 Ralf Baechle
+ * (C) Copyright 1999, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_SEMAPHORE_HELPER_H
 #define _ASM_SEMAPHORE_HELPER_H
@@ -68,63 +68,56 @@
 
 #ifdef __MIPSEB__
 
-        __asm__ __volatile__("
-	.set	push
-	.set	noat
-0:	lld	%1, %2
-	li	%0, 0
-	sll	$1, %1, 0
-	blez	$1, 1f
-	daddiu	%1, %1, -1
-	li	%0, 1
-	b 	2f
-1:
-	beqz	%3, 2f
-	li	%0, %4
-	dli	$1, 0x0000000100000000
-	daddu	%1, %1, $1
-2:
-	scd	%1, %2
-	beqz	%1, 0b
-	.set	pop"
+        __asm__ __volatile__(
+	".set\tpush\t\t\t# waking_non_zero_interruptible\n\t"
+	".set\tnoat\n\t"
+	"0:\tlld\t%1, %2\n\t"
+	"li\t%0, 0\n\t"
+	"sll\t$1, %1, 0\n\t"
+	"blez\t$1, 1f\n\t"
+	"daddiu\t%1, %1, -1\n\t"
+	"li\t%0, 1\n\t"
+	"b\t2f\n\t"
+	"1:\tbeqz\t%3, 2f\n\t"
+	"li\t%0, %4\n\t"
+	"dli\t$1, 0x0000000100000000\n\t"
+	"daddu\t%1, %1, $1\n\t"
+	"2:\tscd\t%1, %2\n\t"
+	"beqz\t%1, 0b\n\t"
+	".set\tpop"
 	: "=&r" (ret), "=&r" (tmp), "=m" (*sem)
 	: "r" (signal_pending(tsk)), "i" (-EINTR));
 
 #elif defined(__MIPSEL__)
 
-	__asm__ __volatile__("
-	.set	push
-	.set	noat
-0:
-	lld	%1, %2
-	li	%0, 0
-	blez	%1, 1f
-	dli	$1, 0x0000000100000000
-	dsubu	%1, %1, $1
-	li	%0, 1
-	b	2f
-1:
-	beqz	%3, 2f
-	li	%0, %4
+	__asm__ __volatile__(
+	".set\tpush\t\t\t# waking_non_zero_interruptible\n\t"
+	".set\t	noat\n"
+	"0:\tlld\t%1, %2\n\t"
+	"li\t%0, 0\n\t"
+	"blez\t%1, 1f\n\t"
+	"dli\t$1, 0x0000000100000000\n\t"
+	"dsubu\t%1, %1, $1\n\t"
+	"li\t%0, 1\n\t"
+	"b\t2f\n"
+	"1:\tbeqz\t%3, 2f\n\t"
+	"li\t%0, %4\n\t"
 	/* 
 	 * It would be nice to assume that sem->count
 	 * is != -1, but we will guard against that case
 	 */
-	daddiu	$1, %1, 1
-	dsll32	$1, $1, 0
-	dsrl32	$1, $1, 0
-	dsrl32	%1, %1, 0
-	dsll32	%1, %1, 0
-	or	%1, %1, $1
-2:
-	scd	%1, %2
-	beqz	%1, 0b
-	.set	pop"
+	"daddiu\t$1, %1, 1\n\t"
+	"dsll32\t$1, $1, 0\n\t"
+	"dsrl32\t$1, $1, 0\n\t"
+	"dsrl32\t%1, %1, 0\n\t"
+	"dsll32\t%1, %1, 0\n\t"
+	"or\t%1, %1, $1\n"
+	"2:\tscd\t%1, %2\n\t"
+	"beqz\t	%1, 0b\n\t"
+	".set\tpop"
 	: "=&r" (ret), "=&r" (tmp), "=m" (*sem)
 	: "r" (signal_pending(tsk)), "i" (-EINTR));
 
-#else
-#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
 #endif
 
 	return ret;
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/semaphore.h linux/include/asm-mips64/semaphore.h
--- v2.4.6/linux/include/asm-mips64/semaphore.h	Tue Apr 17 17:19:31 2001
+++ linux/include/asm-mips64/semaphore.h	Wed Jul  4 11:50:39 2001
@@ -3,8 +3,8 @@
  * for more details.
  *
  * Copyright (C) 1996  Linus Torvalds
- * Copyright (C) 1998, 1999, 2000  Ralf Baechle
- * Copyright (C) 1999, 2000  Silicon Graphics, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001  Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001  Silicon Graphics, Inc.
  */
 #ifndef _ASM_SEMAPHORE_H
 #define _ASM_SEMAPHORE_H
@@ -130,29 +130,25 @@
 	CHECK_MAGIC(sem->__magic);
 #endif
 
-	__asm__ __volatile__("
-			.set	mips3
-
-		0:	lld	%1, %4
-			dli	%3, 0x0000000100000000
-			dsubu	%1, %3
-			li	%0, 0
-			bgez	%1, 2f
-			sll	%2, %1, 0
-			blez	%2, 1f
-			daddiu	%1, %1, -1
-			b	2f
-		1:
-			daddu	%1, %1, %3
-			li	%0, 1
-		2:
-			scd	%1, %4
-			beqz	%1, 0b
-
-			.set	mips0"
-		: "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
-		: "m"(*sem)
-		: "memory");
+	__asm__ __volatile__(
+	".set\tmips3\t\t\t# down_trylock\n"
+	"0:\tlld\t%1, %4\n\t"
+	"\tdli\t%3, 0x0000000100000000\n\t"
+	"\tdsubu\t%1, %3\n\t"
+	"\tli\t%0, 0\n\t"
+	"\tbgez\t%1, 2f\n\t"
+	"\tsll\t%2, %1, 0\n\t"
+	"\tblez\t%2, 1f\n\t"
+	"\tdaddiu\t%1, %1, -1\n\t"
+	"\tb\t2f\n"
+	"1:\tdaddu\t%1, %1, %3\n\t"
+	"\tli\t%0, 1\n"
+	"2:\tscd\t%1, %4\n\t"
+	"\tbeqz\t%1, 0b\n\t"
+	"\t.set\tmips0"
+	: "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
+	: "m"(*sem)
+	: "memory");
 
 	return ret;
 }
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sgi/sgint23.h linux/include/asm-mips64/sgi/sgint23.h
--- v2.4.6/linux/include/asm-mips64/sgi/sgint23.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/sgi/sgint23.h	Wed Jul  4 11:50:39 2001
@@ -170,7 +170,7 @@
 #endif
 #define INT2_TCLEAR_T0CLR      0x1        /* Clear timer0 IRQ */
 #define INT2_TCLEAR_T1CLR      0x2        /* Clear timer1 IRQ */
-/* I am guesing there are only two unused registers here 
+/* I am guessing there are only two unused registers here 
  * but I could be wrong...			- andrewb
  */
 /*	u32 _unused[3]; */
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sgialib.h linux/include/asm-mips64/sgialib.h
--- v2.4.6/linux/include/asm-mips64/sgialib.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/sgialib.h	Wed Jul  4 11:50:39 2001
@@ -1,5 +1,4 @@
-/* $Id: sgialib.h,v 1.3 1999/12/04 03:59:12 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -7,6 +6,7 @@
  * SGI ARCS firmware interface library for the Linux kernel.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 2001 Ralf Baechle (ralf@gnu.org)
  */
 #ifndef _ASM_SGIALIB_H
 #define _ASM_SGIALIB_H
@@ -90,9 +90,9 @@
  */
 extern void prom_identify_arch(void);
 
-/* Environemt variable routines. */
+/* Environment variable routines. */
 extern PCHAR ArcGetEnvironmentVariable(PCHAR name);
-extern LONG SetEnvironmentVariable(PCHAR name, PCHAR value);
+extern LONG ArcSetEnvironmentVariable(PCHAR name, PCHAR value);
 
 /* ARCS command line acquisition and parsing. */
 extern char *prom_getcmdline(void);
@@ -120,11 +120,11 @@
 extern long prom_exec(char *name, long argc, char **argv, char **envp);
 
 /* Misc. routines. */
-extern void prom_halt(VOID) __attribute__((noreturn));
-extern void prom_powerdown(VOID) __attribute__((noreturn));
-extern void prom_restart(VOID) __attribute__((noreturn));
+extern VOID prom_halt(VOID) __attribute__((noreturn));
+extern VOID prom_powerdown(VOID) __attribute__((noreturn));
+extern VOID prom_restart(VOID) __attribute__((noreturn));
 extern VOID ArcReboot(VOID) __attribute__((noreturn));
-extern VOID ArcEnterInteractiveMode(void) __attribute__((noreturn));
+extern VOID ArcEnterInteractiveMode(VOID) __attribute__((noreturn));
 extern long prom_cfgsave(VOID);
 extern struct linux_sysid *prom_getsysid(VOID);
 extern VOID ArcFlushAllCaches(VOID);
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sgiarcs.h linux/include/asm-mips64/sgiarcs.h
--- v2.4.6/linux/include/asm-mips64/sgiarcs.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips64/sgiarcs.h	Wed Jul  4 11:50:39 2001
@@ -143,7 +143,7 @@
 
 /* ARCS virtual dirents. */
 struct linux_vdirent {
-	unsigned long namelen;
+	ULONG namelen;
 	unsigned char attr;
 	char fname[32]; /* XXX imperical, should be a define */
 };
@@ -177,38 +177,38 @@
 	struct linux_bigint   begin;
 	struct linux_bigint   end;
 	struct linux_bigint   cur;
-	enum linux_devtypes dtype;
+	enum linux_devtypes   dtype;
 	unsigned long         namelen;
 	unsigned char         attr;
 	char                  name[32]; /* XXX imperical, should be define */
 };
 
-/* This describes the vector containing fuction pointers to the ARC
+/* This describes the vector containing function pointers to the ARC
    firmware functions.  */
 struct linux_romvec {
-	LONG load;			/* Load an executable image. */
-	LONG invoke;			/* Invoke a standalong image. */
-	LONG exec;			/* Load and begin execution of a
+	LONG	load;			/* Load an executable image. */
+	LONG	invoke;			/* Invoke a standalong image. */
+	LONG	exec;			/* Load and begin execution of a
 					   standalone image. */
-	LONG halt;			/* Halt the machine. */
-	LONG pdown;			/* Power down the machine. */
-	LONG restart;			/* XXX soft reset??? */
-	LONG reboot;			/* Reboot the machine. */
-	LONG imode;			/* Enter PROM interactive mode. */
-	LONG _unused1;			/* Was ReturnFromMain(). */
+	LONG	halt;			/* Halt the machine. */
+	LONG	pdown;			/* Power down the machine. */
+	LONG	restart;		/* XXX soft reset??? */
+	LONG	reboot;			/* Reboot the machine. */
+	LONG	imode;			/* Enter PROM interactive mode. */
+	LONG	_unused1;		/* Was ReturnFromMain(). */
 
 	/* PROM device tree interface. */
-	LONG next_component;
-	LONG child_component;
-	LONG parent_component;
-	LONG component_data;
-	LONG child_add;
-	LONG comp_del;
-	LONG component_by_path;
+	LONG	next_component;
+	LONG	child_component;
+	LONG	parent_component;
+	LONG	component_data;
+	LONG	child_add;
+	LONG	comp_del;
+	LONG	component_by_path;
 
 	/* Misc. stuff. */
-	LONG cfg_save;
-	LONG get_sysid;
+	LONG	cfg_save;
+	LONG	get_sysid;
 
 	/* Probing for memory. */
 	LONG	get_mdesc;
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/siginfo.h linux/include/asm-mips64/siginfo.h
--- v2.4.6/linux/include/asm-mips64/siginfo.h	Wed May 24 18:38:26 2000
+++ linux/include/asm-mips64/siginfo.h	Wed Jul  4 11:50:39 2001
@@ -1,10 +1,10 @@
-/* $Id: siginfo.h,v 1.2 2000/01/27 01:05:37 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1998, 1999 by Ralf Baechle
+ * Copyright (C) 1998, 1999, 2001 Ralf Baechle
+ * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_SIGINFO_H
 #define _ASM_SIGINFO_H
@@ -62,7 +62,7 @@
 
 		/* SIGPOLL, SIGXFSZ (To do ...)  */
 		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			long _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
 			int _fd;
 		} _sigpoll;
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/smp.h linux/include/asm-mips64/smp.h
--- v2.4.6/linux/include/asm-mips64/smp.h	Fri Mar  2 11:30:15 2001
+++ linux/include/asm-mips64/smp.h	Wed Jul  4 11:50:39 2001
@@ -1,3 +1,12 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
+ * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
+ */
+
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
 
@@ -38,12 +47,42 @@
 extern int __cpu_logical_map[NR_CPUS];
 #define cpu_logical_map(cpu)  __cpu_logical_map[cpu]
 
-/* Good enough for toy^Wupto 64 CPU Origins.  */
-extern unsigned long cpu_present_mask;
-#define cpu_online_map cpu_present_mask
-
 #endif
 
 #define NO_PROC_ID	(-1)
 
-#endif __ASM_SMP_H
+#if (NR_CPUS <= _MIPS_SZLONG)
+
+typedef unsigned long   cpumask_t;
+
+#define CPUMASK_CLRALL(p)	(p) = 0
+#define CPUMASK_SETB(p, bit)	(p) |= 1 << (bit)
+#define CPUMASK_CLRB(p, bit)	(p) &= ~(1ULL << (bit))
+#define CPUMASK_TSTB(p, bit)	((p) & (1ULL << (bit)))
+
+#elif (NR_CPUS <= 128)
+
+/*
+ * The foll should work till 128 cpus.
+ */
+#define CPUMASK_SIZE		(NR_CPUS/_MIPS_SZLONG)
+#define CPUMASK_INDEX(bit)	((bit) >> 6)
+#define CPUMASK_SHFT(bit)	((bit) & 0x3f)
+
+typedef struct {
+	unsigned long	_bits[CPUMASK_SIZE];
+} cpumask_t;
+
+#define	CPUMASK_CLRALL(p)	(p)._bits[0] = 0, (p)._bits[1] = 0
+#define CPUMASK_SETB(p, bit)	(p)._bits[CPUMASK_INDEX(bit)] |= \
+					(1ULL << CPUMASK_SHFT(bit))
+#define CPUMASK_CLRB(p, bit)	(p)._bits[CPUMASK_INDEX(bit)] &= \
+					~(1ULL << CPUMASK_SHFT(bit))
+#define CPUMASK_TSTB(p, bit)	((p)._bits[CPUMASK_INDEX(bit)] & \
+					(1ULL << CPUMASK_SHFT(bit)))
+
+#else
+#error cpumask macros only defined for 128p kernels
+#endif
+
+#endif /* __ASM_SMP_H */
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sn/types.h linux/include/asm-mips64/sn/types.h
--- v2.4.6/linux/include/asm-mips64/sn/types.h	Sun Jul  9 22:18:15 2000
+++ linux/include/asm-mips64/sn/types.h	Wed Jul  4 11:50:39 2001
@@ -13,7 +13,6 @@
 #include <linux/types.h>
 
 typedef unsigned long 	cpuid_t;
-typedef unsigned long 	cpumask_t;
 typedef unsigned long	cnodemask_t;
 typedef signed short	nasid_t;	/* node id in numa-as-id space */
 typedef signed short	cnodeid_t;	/* node id in compact-id space */
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/socket.h linux/include/asm-mips64/socket.h
--- v2.4.6/linux/include/asm-mips64/socket.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-mips64/socket.h	Wed Jul  4 11:50:39 2001
@@ -3,8 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1997, 1999, 2000 Ralf Baechle
- * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1997, 1999, 2000, 2001 Ralf Baechle
+ * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
@@ -41,7 +41,7 @@
 #define SO_RCVLOWAT	0x1004	/* receive low-water mark */
 #define SO_SNDTIMEO	0x1005	/* send timeout */
 #define SO_RCVTIMEO 	0x1006	/* receive timeout */
-#define SO_ACCEPTCONN	0x1007
+#define SO_ACCEPTCONN	0x1009
 
 /* linux-specific, might as well be the same as on i386 */
 #define SO_NO_CHECK	11
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/system.h linux/include/asm-mips64/system.h
--- v2.4.6/linux/include/asm-mips64/system.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/system.h	Wed Jul  4 11:50:39 2001
@@ -33,7 +33,7 @@
 }
 
 /*
- * For cli() we have to insert nops to make shure that the new value
+ * For cli() we have to insert nops to make sure that the new value
  * has actually arrived in the status register before the end of this
  * macro.
  * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/termios.h linux/include/asm-mips64/termios.h
--- v2.4.6/linux/include/asm-mips64/termios.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-mips64/termios.h	Wed Jul  4 11:50:39 2001
@@ -1,10 +1,10 @@
-/* $Id: termios.h,v 1.2 2000/01/27 23:45:30 ralf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_TERMIOS_H
 #define _ASM_TERMIOS_H
diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/unaligned.h linux/include/asm-mips64/unaligned.h
--- v2.4.6/linux/include/asm-mips64/unaligned.h	Tue Nov 28 21:42:04 2000
+++ linux/include/asm-mips64/unaligned.h	Wed Jul  4 11:50:39 2001
@@ -3,8 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1996, 1999, 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_UNALIGNED_H
 #define _ASM_UNALIGNED_H
@@ -84,8 +84,15 @@
 		: "r" (__val));
 }
 
-/* 
- * The main single-value unaligned transfer routines.
+/*
+ * get_unaligned - get value from possibly mis-aligned location
+ * @ptr: pointer to value
+ *
+ * This macro should be used for accessing values larger in size than 
+ * single bytes at locations that are expected to be improperly aligned, 
+ * e.g. retrieving a u16 value from a location not u16-aligned.
+ *
+ * Note that unaligned accesses can be very expensive on some architectures.
  */
 #define get_unaligned(ptr)						\
 ({									\
@@ -102,7 +109,7 @@
 		__val = __ldl_u((const unsigned int *)(ptr));		\
 		break;							\
 	case 8:								\
-		__val = __ldq_u((const unsigned long long *)(ptr));	\
+		__val = __ldq_u((const unsigned long *)(ptr));		\
 		break;							\
 	default:							\
 		__get_unaligned_bad_length();				\
@@ -112,6 +119,17 @@
 	__val;								\
 })
 
+/*
+ * put_unaligned - put value to a possibly mis-aligned location
+ * @val: value to place
+ * @ptr: pointer to location
+ *
+ * This macro should be used for placing values larger in size than 
+ * single bytes at locations that are expected to be improperly aligned, 
+ * e.g. writing a u16 value to a location not u16-aligned.
+ *
+ * Note that unaligned accesses can be very expensive on some architectures.
+ */
 #define put_unaligned(val,ptr)						\
 do {									\
 	switch (sizeof(*(ptr))) {					\
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h
--- v2.4.6/linux/include/asm-s390/bitops.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/bitops.h	Wed Jul  4 11:50:39 2001
@@ -34,7 +34,14 @@
  * align the address to 4 byte boundary. It seems to work
  * without the alignment. 
  */
+#ifdef __KERNEL__
 #define ALIGN_CS 0
+#else
+#define ALIGN_CS 1
+#ifndef CONFIG_SMP
+#error "bitops won't work without CONFIG_SMP"
+#endif
+#endif
 
 /* bitmap tables from arch/S390/kernel/bitmap.S */
 extern const char _oi_bitmap[];
@@ -487,6 +494,7 @@
              : "cc", "memory", "1", "2" );
         return oldbit;
 }
+#define __test_and_set_bit(X,Y)		test_and_set_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_clear_bit routine
@@ -513,6 +521,7 @@
              : "cc", "memory", "1", "2" );
         return oldbit;
 }
+#define __test_and_clear_bit(X,Y)	test_and_clear_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_change_bit routine
@@ -539,6 +548,7 @@
              : "cc", "memory", "1", "2" );
         return oldbit;
 }
+#define __test_and_change_bit(X,Y)	test_and_change_bit_simple(X,Y)
 
 #ifdef CONFIG_SMP
 #define set_bit             set_bit_cs
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/ebcdic.h linux/include/asm-s390/ebcdic.h
--- v2.4.6/linux/include/asm-s390/ebcdic.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/ebcdic.h	Wed Jul  4 11:50:39 2001
@@ -29,8 +29,8 @@
         __asm__ __volatile__(
 		"   bras 1,1f\n"
 		"   tr   0(1,%0),0(%2)\n"
-		"0: la   %0,256(%0)\n"
-                "   tr   0(256,%0),0(%2)\n"
+                "0: tr   0(256,%0),0(%2)\n"
+		"   la   %0,256(%0)\n"
 		"1: ahi  %1,-256\n"
 		"   jp   0b\n"
 		"   ex   %1,0(1)"
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/pci.h linux/include/asm-s390/pci.h
--- v2.4.6/linux/include/asm-s390/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/pci.h	Wed Jul  4 11:50:39 2001
@@ -0,0 +1,9 @@
+#ifndef __ASM_S390_PCI_H
+#define __ASM_S390_PCI_H
+
+/* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code
+ * includes it even if CONFIG_PCI is not set.
+ */
+
+#endif /* __ASM_S390_PCI_H */
+
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/bitops.h linux/include/asm-s390x/bitops.h
--- v2.4.6/linux/include/asm-s390x/bitops.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/bitops.h	Wed Jul  4 11:50:39 2001
@@ -38,7 +38,14 @@
  * align the address to 4 byte boundary. It seems to work
  * without the alignment. 
  */
+#ifdef __KERNEL__
 #define ALIGN_CS 0
+#else
+#define ALIGN_CS 1
+#ifndef CONFIG_SMP
+#error "bitops won't work without CONFIG_SMP"
+#endif
+#endif
 
 /* bitmap tables from arch/S390/kernel/bitmap.S */
 extern const char _oi_bitmap[];
@@ -54,7 +61,7 @@
         unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lghi  %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
              "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
              "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
              "   sllg  %2,%2,3\n"
@@ -84,7 +91,7 @@
         unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lghi  %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
              "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
              "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
              "   sllg  %2,%2,3\n"
@@ -115,7 +122,7 @@
         unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lghi  %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
              "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
              "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
              "   sllg  %2,%2,3\n"
@@ -146,7 +153,7 @@
         unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lghi  %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
              "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
              "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
              "   sllg  %2,%2,3\n"
@@ -179,7 +186,7 @@
         unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lghi  %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
              "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
              "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
              "   sllg  %2,%2,3\n"
@@ -212,7 +219,7 @@
         unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lghi  %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
              "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
              "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
              "   sllg  %2,%2,3\n"
@@ -494,6 +501,7 @@
              : "cc", "memory", "1", "2" );
         return oldbit & 1;
 }
+#define __test_and_set_bit(X,Y)		test_and_set_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_clear_bit routine
@@ -518,6 +526,7 @@
              : "cc", "memory", "1", "2" );
         return oldbit & 1;
 }
+#define __test_and_clear_bit(X,Y)	test_and_clear_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_change_bit routine
@@ -542,6 +551,7 @@
              : "cc", "memory", "1", "2" );
         return oldbit & 1;
 }
+#define __test_and_change_bit(X,Y)	test_and_change_bit_simple(X,Y)
 
 #ifdef CONFIG_SMP
 #define set_bit             set_bit_cs
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/byteorder.h linux/include/asm-s390x/byteorder.h
--- v2.4.6/linux/include/asm-s390x/byteorder.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/byteorder.h	Wed Jul  4 11:50:39 2001
@@ -36,9 +36,9 @@
 static __inline__ void ___arch__swab64s(__u64 *x)
 {
   __asm__ __volatile__ (
-          "   lrvg %0,%1\n"
-	  "   stg  %0,%1"
-          : : "m" (*x) : "memory");
+          "   lrvg 0,%0\n"
+	  "   stg  0,%0"
+          : "+m" (*x) : : "0");
 }
 
 static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
@@ -64,9 +64,9 @@
 static __inline__ void ___arch__swab32s(__u32 *x)
 {
   __asm__ __volatile__ (
-          "   lrv  %0,%1\n"
-	  "   st   %0,%1"
-          : : "m" (*x) : "memory");
+          "   lrv  0,%0\n"
+	  "   st   0,%0"
+          : "+m" (*x) : : "0" );
 }
 
 static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
@@ -92,15 +92,18 @@
 static __inline__ void ___arch__swab16s(__u16 *x)
 {
   __asm__ __volatile__ (
-          "   lrvh %0,%1\n"
-	  "   sth  %0,%1"
-          : : "m" (*x) : "memory");
+          "   lrvh 0,%0\n"
+	  "   sth  0,%0"
+          : "+m" (*x) : : "0" );
 }
 
+#define __arch__swab64(x) ___arch__swab64(x)
 #define __arch__swab32(x) ___arch__swab32(x)
 #define __arch__swab16(x) ___arch__swab16(x)
+#define __arch__swab64p(x) ___arch__swab64p(x)
 #define __arch__swab32p(x) ___arch__swab32p(x)
 #define __arch__swab16p(x) ___arch__swab16p(x)
+#define __arch__swab64s(x) ___arch__swab64s(x)
 #define __arch__swab32s(x) ___arch__swab32s(x)
 #define __arch__swab16s(x) ___arch__swab16s(x)
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/ebcdic.h linux/include/asm-s390x/ebcdic.h
--- v2.4.6/linux/include/asm-s390x/ebcdic.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/ebcdic.h	Wed Jul  4 11:50:39 2001
@@ -29,8 +29,8 @@
         __asm__ __volatile__(
 		"   bras  1,1f\n"
 		"   tr    0(1,%0),0(%2)\n"
-		"0: la    %0,256(%0)\n"
-		"   tr    0(256,%0),0(%2)\n"
+		"0: tr    0(256,%0),0(%2)\n"
+		"   la    %0,256(%0)\n"
 		"1: ahi   %1,-256\n"
 		"   jp    0b\n"
 		"   ex    %1,0(1)"
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/irq.h linux/include/asm-s390x/irq.h
--- v2.4.6/linux/include/asm-s390x/irq.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/irq.h	Wed Jul  4 11:50:39 2001
@@ -889,9 +889,9 @@
         spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
-#endif /* __KERNEL__ */
 
 #define touch_nmi_watchdog() do { } while(0)
 
+#endif /* __KERNEL__ */
 #endif
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/string.h linux/include/asm-s390x/string.h
--- v2.4.6/linux/include/asm-s390x/string.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/string.h	Wed Jul  4 11:50:39 2001
@@ -45,8 +45,6 @@
 extern char *strncpy(char *, const char *, size_t);
 extern int strcmp(const char *,const char *);
 
-#undef __HAVE_ARCH_MEMCHR
-#if 0
 static inline void * memchr(const void * cs,int c,size_t count)
 {
     void *ptr;
@@ -63,7 +61,6 @@
                           : "cc", "0", "1" );
     return ptr;
 }
-#endif
 
 static __inline__ char *strcpy(char *dest, const char *src)
 {
@@ -77,8 +74,6 @@
     return tmp;
 }
 
-#undef __HAVE_ARCH_STRLEN
-#if 0
 static __inline__ size_t strlen(const char *s)
 {
     size_t len;
@@ -93,10 +88,7 @@
                           : "cc", "0" );
     return len;
 }
-#endif
 
-#undef __HAVE_ARCH_STRCAT
-#if 0
 static __inline__ char *strcat(char *dest, const char *src)
 {
     char *tmp = dest;
@@ -112,7 +104,6 @@
                           : "cc", "memory", "0" );
     return tmp;
 }
-#endif
 
 extern void *alloca(size_t);
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h
--- v2.4.6/linux/include/asm-sparc/vaddrs.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-sparc/vaddrs.h	Fri Jul  6 16:46:22 2001
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.26 2000/08/01 04:53:58 anton Exp $ */
+/* $Id: vaddrs.h,v 1.27 2001/07/04 00:18:18 davem Exp $ */
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc64/starfire.h linux/include/asm-sparc64/starfire.h
--- v2.4.6/linux/include/asm-sparc64/starfire.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-sparc64/starfire.h	Fri Jul  6 16:46:22 2001
@@ -1,4 +1,4 @@
-/* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $
+/* $Id: starfire.h,v 1.2 2001/07/04 00:18:18 davem Exp $
  * starfire.h: Group all starfire specific code together.
  *
  * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
diff -u --recursive --new-file v2.4.6/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h
--- v2.4.6/linux/include/linux/apm_bios.h	Fri Apr  6 10:51:19 2001
+++ linux/include/linux/apm_bios.h	Wed Jul  4 11:50:39 2001
@@ -52,6 +52,9 @@
 	struct apm_bios_info	bios;
 	unsigned short		connection_version;
 	int			get_power_status_broken;
+	int			allow_ints;
+	int			realmode_power_off;
+	int			disabled;
 };
 
 /*
diff -u --recursive --new-file v2.4.6/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.4.6/linux/include/linux/hdreg.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/hdreg.h	Mon Jul  9 11:38:56 2001
@@ -98,6 +98,7 @@
 #define SMART_IMMEDIATE_OFFLINE	0xd4
 #define SMART_READ_LOG_SECTOR	0xd5
 #define SMART_WRITE_LOG_SECTOR	0xd6
+#define SMART_WRITE_THRESHOLDS	0xd7
 #define SMART_ENABLE		0xd8
 #define SMART_DISABLE		0xd9
 #define SMART_STATUS		0xda
@@ -159,6 +160,7 @@
 #define ABRT_ERR	0x04	/* Command aborted */
 #define MCR_ERR		0x08	/* media change request */
 #define ID_ERR		0x10	/* ID field not found */
+#define MC_ERR		0x20	/* media changed */
 #define ECC_ERR		0x40	/* Uncorrectable ECC error */
 #define	BBD_ERR		0x80	/* pre-EIDE meaning:  block marked bad */
 #define	ICRC_ERR	0x80	/* new meaning:  CRC error during transfer */
@@ -174,6 +176,7 @@
 #define HDIO_GETGEO		0x0301	/* get device geometry */
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
 #define HDIO_GET_MULTCOUNT	0x0304	/* get current IDE blockmode setting */
+#define HDIO_GET_QDMA		0x0305	/* get use-qdma flag */
 #define HDIO_OBSOLETE_IDENTITY	0x0307	/* OBSOLETE, DO NOT USE: returns 142 bytes */
 #define HDIO_GET_KEEPSETTINGS	0x0308	/* get keep-settings-on-reset flag */
 #define HDIO_GET_32BIT		0x0309	/* get current io_32bit setting */
@@ -181,9 +184,13 @@
 #define HDIO_GET_DMA		0x030b	/* get use-dma flag */
 #define HDIO_GET_NICE		0x030c	/* get nice flags */
 #define HDIO_GET_IDENTITY	0x030d	/* get IDE identification info */
+#define HDIO_GET_WCACHE		0x030e	/* get write cache mode on|off */
+#define HDIO_GET_ACOUSTIC	0x030f	/* get acoustic value */
 
+#define HDIO_GET_BUSSTATE	0x031a	/* get the bus state of the hwif */
+#define HDIO_TRISTATE_HWIF	0x031b	/* OBSOLETE - use SET_BUSSTATE */
 #define HDIO_DRIVE_RESET	0x031c	/* execute a device reset */
-#define HDIO_TRISTATE_HWIF	0x031d	/* execute a channel tristate */
+#define HDIO_DRIVE_TASKFILE	0x031d	/* execute raw taskfile */
 #define HDIO_DRIVE_TASK		0x031e	/* execute task and special drive command */
 #define HDIO_DRIVE_CMD		0x031f	/* execute a special drive command */
 
@@ -200,6 +207,17 @@
 #define HDIO_SCAN_HWIF		0x0328	/* register and (re)scan interface */
 #define HDIO_SET_NICE		0x0329	/* set nice flags */
 #define HDIO_UNREGISTER_HWIF	0x032a  /* unregister interface */
+#define HDIO_SET_WCACHE		0x032b	/* change write cache enable-disable */
+#define HDIO_SET_ACOUSTIC	0x032c	/* change acoustic behavior */
+#define HDIO_SET_BUSSTATE	0x032d	/* set the bus state of the hwif */
+#define HDIO_SET_QDMA		0x032e	/* change use-qdma flag */
+
+/* bus states */
+enum {
+	BUSSTATE_OFF = 0,
+	BUSSTATE_ON,
+	BUSSTATE_TRISTATE
+};
 
 /* BIG GEOMETRY */
 struct hd_big_geometry {
diff -u --recursive --new-file v2.4.6/linux/include/linux/ibmtr.h linux/include/linux/ibmtr.h
--- v2.4.6/linux/include/linux/ibmtr.h	Tue Jul  3 17:08:21 2001
+++ linux/include/linux/ibmtr.h	Wed Jul  4 11:50:39 2001
@@ -6,26 +6,22 @@
 
 /* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */
 
-#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */
-#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
-#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
-#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
-#define TR_RETRIES 6            /* number of open retries */ 
+#define TR_RETRY_INTERVAL	(30*HZ)	/* 500 on PC = 5 s */
+#define TR_RST_TIME		(HZ/20) /* 5 on PC = 50 ms */
+#define TR_BUSY_INTERVAL	(HZ/5)	/* 5 on PC = 200 ms */
+#define TR_SPIN_INTERVAL	(3*HZ)	/* 3 seconds before init timeout */
 
 #define TR_ISA 1
 #define TR_MCA 2
 #define TR_ISAPNP 3
 #define NOTOK 0
-#define TOKDEBUG 1
 
 #define IBMTR_SHARED_RAM_SIZE 0x10000
 #define IBMTR_IO_EXTENT 4
-#define IBMTR_MAX_ADAPTERS 2
+#define IBMTR_MAX_ADAPTERS 4
 
 #define CHANNEL_ID      0X1F30
 #define AIP             0X1F00
-#define AIPCHKSUM1      0X1F60
-#define AIPCHKSUM2      0X1FF0
 #define AIPADAPTYPE     0X1FA0
 #define AIPDATARATE     0X1FA2
 #define AIPEARLYTOKEN   0X1FA4
@@ -35,22 +31,17 @@
 #define AIP16MBDHB      0X1FAC
 #define AIPFID		0X1FBA
 
-/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits.  I left everything
-   the way my documentation had it, ie: 0x0A20.     */
-#define ADAPTINTCNTRL   0x02f0  /* Adapter interrupt control */
 #define ADAPTRESET      0x1     /* Control Adapter reset (add to base) */
 #define ADAPTRESETREL   0x2     /* Release Adapter from reset ( """)  */
 #define ADAPTINTREL	0x3 	/* Adapter interrupt release */
 
-#define MMIOStartLocP   0x0a20  /* Primary adapter's starting MMIO area */
-#define MMIOStartLocA   0x0a24  /* Alternate adapter's starting MMIO area */
-
 #define GLOBAL_INT_ENABLE 0x02f0
 
 /* MMIO bits 0-4 select register */
-#define RRR_EVEN        0x00    /* Shared RAM relocation registers - even and odd */
+#define RRR_EVEN       0x00 /* Shared RAM relocation registers - even and odd */
 /* Used to set the starting address of shared RAM  */
-/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/
+/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared
+   RAM address.*/
 /* ie: 0x02 sets RAM address to ...ato!  issy su wazzoo !! GODZILLA!!! */
 #define RRR_ODD         0x01
 /* Bits 2 and 3 of this register can be read to determine shared RAM size */
@@ -59,28 +50,26 @@
 #define WRBR_ODD        0x03
 #define WWOR_EVEN       0x04    /* Write window open registers - even and odd */
 #define WWOR_ODD        0x05
-#define WWCR_EVEN       0x06    /* Write window close registers - even and odd */
+#define WWCR_EVEN       0x06   /* Write window close registers - even and odd */
 #define WWCR_ODD        0x07
 
 /* Interrupt status registers - PC system  - even and odd */
 #define ISRP_EVEN       0x08
 
-#define TCR_INT 0x10    /* Bit 4 - Timer interrupt.  The TVR_EVEN timer has
+#define TCR_INT    0x10    /* Bit 4 - Timer interrupt.  The TVR_EVEN timer has
                                                                    expired. */
-#define ERR_INT 0x08    /* Bit 3 - Error interrupt.  The adapter has had an
-                                                                   internal error. */
+#define ERR_INT	   0x08    /* Bit 3 - Error interrupt.  The adapter has had an
+                                                            internal error. */
 #define ACCESS_INT 0x04    /* Bit 2 - Access interrupt.  You have attempted to
-                                                           write to an invalid area of shared RAM or an invalid
-                                                                   register within the MMIO. */
-/*      In addition, the following bits within ISRP_EVEN can be turned on or off by you */
-/*      to control the interrupt processing:   */
-#define INT_IRQ 0x80    /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and
-                                                              IRQ.  This should normally be set (by you) to 1.  */
+				      write to an invalid area of shared RAM
+				      or an invalid register within the MMIO. */
+/* In addition, the following bits within ISRP_EVEN can be turned on or off   */
+/* by you to control the interrupt processing:   */
 #define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable.  If 0, no interrupts will
-                                                                   occur.  If 1, interrupts will occur normally.
-                                                                   Normally set to 1.  */
-/* Bit 0 - Primary or alternate adapter.  Set to zero if this adapter is the primary adapter,*/
-/*         1 if this adapter is the alternate adapter. */
+                                   occur.  If 1, interrupts will occur normally.
+                                                         Normally set to 1.  */
+/* Bit 0 - Primary or alternate adapter.  Set to zero if this adapter is the
+		primary adapter, 1 if this adapter is the alternate adapter. */
 
 
 #define ISRP_ODD        0x09
@@ -92,21 +81,21 @@
                              an SRB request and set the return code within
                              the SRB. */
 #define ASB_FREE_INT 0x10 /* Bit 4 - ASB free.  The adapter has read the ASB
-                                                                          and this area can be safely reused. This interrupt
-                                                                          is only used if your application has set the ASB
-                                                                          free request bit in ISRA_ODD or if an error was
-                                                                detected in your response. */
+                             and this area can be safely reused. This interrupt
+                             is only used if your application has set the ASB
+                             free request bit in ISRA_ODD or if an error was
+                             detected in your response. */
 #define ARB_CMD_INT  0x08 /* Bit 3 - ARB command.  The adapter has given you a
-                                                                          command for action.  The command is located in the
-                                                                          ARB area of shared memory. */
+                             command for action.  The command is located in the
+                             ARB area of shared memory. */
 #define SSB_RESP_INT 0x04 /* Bit 2 - SSB response.  The adapter has posted a
-                                                                          response to your SRB (the response is located in
-                                                                          the SSB area of shared memory). */
+                             response to your SRB (the response is located in
+                             the SSB area of shared memory). */
 /* Bit 1 - Bridge frame forward complete. */
 
 
 
-#define ISRA_EVEN       0x0A    /* Interrupt status registers - adapter  - even and odd */
+#define ISRA_EVEN 0x0A /*Interrupt status registers - adapter  - even and odd */
 /* Bit 7 - Internal parity error (on adapter's internal bus) */
 /* Bit 6 - Timer interrupt pending */
 /* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */
@@ -114,21 +103,21 @@
 /* Bit 3 - Adapter processor check status */
 /* Bit 2 - Reserved */
 /* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */
-/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */
+/* Bit 0 - Adapter software interrupt mask (prevents internal software ints) */
 
 #define ISRA_ODD        0x0B
-#define CMD_IN_SRB 0x20 /* Bit 5  - Indicates that you have placed a new
+#define CMD_IN_SRB  0x20 /* Bit 5  - Indicates that you have placed a new
                            command in the SRB and are ready for the adapter to
                            process the command. */
 #define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response
-                                                                    (an ASB) in the shared RAM which is available for
-                                                                         the adapter's use. */
-/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */
-/*         command is still pending.  The adapter will then interrupt you when the previous */
-/*         command is completed */
-/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */
-/*         ASB is still pending.  The adapter will then interrupt you when the previous ASB */
-/*         is copied.  */
+                            (an ASB) in the shared RAM which is available for
+                            the adapter's use. */
+/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but
+	that a previous command is still pending.  The adapter will then
+	interrupt you when the previous command is completed */
+/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but
+	that a previous ASB is still pending.  The adapter will then interrupt
+	you when the previous ASB is copied.  */
 #define ARB_FREE 0x2
 #define SSB_FREE 0x1
 
@@ -138,7 +127,7 @@
 #define TVR_ODD         0x0F
 #define SRPR_EVEN       0x18    /* Shared RAM paging registers - even and odd */
 #define SRPR_ENABLE_PAGING 0xc0
-#define SRPR_ODD        0x19 /* Not used. */
+#define SRPR_ODD        0x19	/* Not used. */
 #define TOKREAD         0x60
 #define TOKOR           0x40
 #define TOKAND          0x20
@@ -153,7 +142,8 @@
 /* MMIO bits 7-8 select area of interest.. see below */
 /* 00 selects attachment control area. */
 /* 01 is reserved. */
-/* 10 selects adapter identification area A containing the adapter encoded address. */
+/* 10 selects adapter identification area A containing the adapter encoded
+	address. */
 /* 11 selects the adapter identification area B containing test patterns. */
 
 #define PCCHANNELID 5049434F3631313039393020
@@ -165,18 +155,18 @@
 #define ACA_RW 0x00
 
 #ifdef ENABLE_PAGING
-#define SET_PAGE(x) (isa_writeb((x), \
-  ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN))
+#define SET_PAGE(x) (writeb((x), ti->mmio + ACA_OFFSET+ ACA_RW + SRPR_EVEN))
 #else
 #define SET_PAGE(x)
 #endif
 
-typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state;
-
 /* do_tok_int possible values */
 #define FIRST_INT 1
 #define NOT_FIRST 2
 
+typedef enum {	CLOSED,	OPEN } open_state;
+//staic const char *printstate[] = { "CLOSED","OPEN"};
+
 struct tok_info {
 	unsigned char irq;
 	__u32 mmio;
@@ -186,6 +176,7 @@
 	unsigned char token_release;
 	unsigned char avail_shared_ram;
 	unsigned char shared_ram_paging;
+        unsigned char turbo;
 	unsigned short dhb_size4mb;
 	unsigned short rbuf_len4;
 	unsigned short rbuf_cnt4;
@@ -196,14 +187,13 @@
 	unsigned short maxmtu16;
 	/* Additions by David Morris       */
 	unsigned char do_tok_int;
-	wait_queue_head_t wait_for_tok_int;
 	wait_queue_head_t wait_for_reset;
 	unsigned char sram_base;
 	/* Additions by Peter De Schrijver */
 	unsigned char page_mask;          /* mask to select RAM page to Map*/
 	unsigned char mapped_ram_size;    /* size of RAM page */
-	__u32 sram;                       /* Shared memory base address */
-	__u32 init_srb;                   /* Initial System Request Block address */
+	__u32 sram_virt;                  /* Shared memory base address */
+	__u32 init_srb;               /* Initial System Request Block address */
 	__u32 srb;                        /* System Request Block address */
 	__u32 ssb;                        /* System Status Block address */
 	__u32 arb;                        /* Adapter Request Block address */
@@ -217,14 +207,15 @@
 	unsigned short global_int_enable;
 	struct sk_buff *current_skb;
 	struct net_device_stats tr_stats;
-	unsigned char auto_ringspeedsave;
-	open_state open_status;
+	unsigned char auto_speedsave;
+	open_state			open_status, sap_status;
+	enum {MANUAL, AUTOMATIC}	open_mode;
+	enum {FAIL, RESTART, REOPEN}	open_action;
+	enum {NO, YES}			open_failure;
 	unsigned char readlog_pending;
 	unsigned short adapter_int_enable; /* Adapter-specific int enable */
         struct timer_list tr_timer;
 	unsigned char ring_speed;
-	__u32 func_addr;
-	unsigned int retry_count;
 	spinlock_t lock;		/* SMP protection */
 };
 
@@ -311,18 +302,6 @@
 	unsigned char product_id[18];
 };
 
-struct srb_open_response {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2[3];
-	__u16 error_code;
-	__u16 asb_addr;
-	__u16 srb_addr;
-	__u16 arb_addr;
-	__u16 ssb_addr;
-};
-
 struct dlc_open_sap {
 	unsigned char command;
 	unsigned char reserved1;
@@ -353,49 +332,6 @@
 	__u16 station_id;
 };
 
-struct srb_interrupt {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char ret_code;
-};
-
-struct srb_read_log {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-	unsigned char reserved2;
-	unsigned char line_errors;
-	unsigned char internal_errors;
-	unsigned char burst_errors;
-	unsigned char A_C_errors;
-	unsigned char abort_delimiters;
-	unsigned char reserved3;
-	unsigned char lost_frames;
-	unsigned char recv_congest_count;
-	unsigned char frame_copied_errors;
-	unsigned char frequency_errors;
-	unsigned char token_errors;
-};
-
-struct asb_xmit_resp {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char ret_code;
-	unsigned char reserved;
-	__u16 station_id;
-	__u16 frame_length;
-	unsigned char hdr_length;
-	unsigned char rsap_value;
-};
-
-struct arb_xmit_req {
-	unsigned char command;
-	unsigned char cmd_corr;
-	unsigned char reserved1[2];
-	__u16 station_id;
-	__u16 dhb_address;
-};
-
 struct arb_rec_req {
 	unsigned char command;
 	unsigned char reserved1[3];
@@ -417,36 +353,14 @@
 };
 
 struct rec_buf {
-  /*	unsigned char reserved1[2]; */
+  	unsigned char reserved1[2];
 	__u16 buf_ptr;
 	unsigned char reserved2;
+	unsigned char receive_fs;
 	__u16 buf_len;
 	unsigned char data[0];
 };
 
-struct arb_dlc_status {
-	unsigned char command;
-	unsigned char reserved1[3];
-	__u16 station_id;
-	__u16 status;
-	unsigned char frmr_data[5];
-	unsigned char access_prio;
-	unsigned char rem_addr[TR_ALEN];
-	unsigned char rsap_value;
-};
-
-struct arb_ring_stat_change {
-	unsigned char command;
-	unsigned char reserved1[5];
-	__u16 ring_status;
-};
-
-struct srb_close_adapter {
-	unsigned char command;
-	unsigned char reserved1;
-	unsigned char ret_code;
-};
-
 struct srb_set_funct_addr {
 	unsigned char command;
 	unsigned char reserved1;
@@ -455,4 +369,4 @@
 	unsigned char funct_address[4];
 };
 
-#endif /* __LINUX_IBMTR_H__ */
+#endif
diff -u --recursive --new-file v2.4.6/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.4.6/linux/include/linux/if_arp.h	Tue Jul  3 17:08:21 2001
+++ linux/include/linux/if_arp.h	Mon Jul  9 11:39:42 2001
@@ -35,6 +35,7 @@
 #define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/
 #define	ARPHRD_ARCNET	7		/* ARCnet			*/
 #define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/
+#define	ARPHRD_IEEE1394	9		/* IEEE 1394 IPv4 - RFC 2734	*/
 #define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/
 #define ARPHRD_ATM	19		/* ATM 				*/
 #define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/
diff -u --recursive --new-file v2.4.6/linux/include/linux/isdnif.h linux/include/linux/isdnif.h
--- v2.4.6/linux/include/linux/isdnif.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/isdnif.h	Fri Jul  6 17:01:06 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.37.6.4 2001/06/09 15:14:19 kai Exp $
+/* $Id: isdnif.h,v 1.37.6.5 2001/06/11 22:08:38 kai Exp $
 
  * Linux ISDN subsystem
  *
diff -u --recursive --new-file v2.4.6/linux/include/linux/locks.h linux/include/linux/locks.h
--- v2.4.6/linux/include/linux/locks.h	Fri May 25 18:02:03 2001
+++ linux/include/linux/locks.h	Mon Jul  9 11:39:02 2001
@@ -26,13 +26,7 @@
 		__wait_on_buffer(bh);
 }
 
-extern inline void unlock_buffer(struct buffer_head *bh)
-{
-	clear_bit(BH_Lock, &bh->b_state);
-	smp_mb__after_clear_bit();
-	if (waitqueue_active(&bh->b_wait))
-		wake_up(&bh->b_wait);
-}
+extern void unlock_buffer(struct buffer_head *bh);
 
 /*
  * super-block locking. Again, interrupts may only unlock
diff -u --recursive --new-file v2.4.6/linux/include/linux/meye.h linux/include/linux/meye.h
--- v2.4.6/linux/include/linux/meye.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/meye.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,57 @@
+/* 
+ * Motion Eye video4linux driver for Sony Vaio PictureBook
+ *
+ * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ * 
+ * Some parts borrowed from various video4linux drivers, especially
+ * bttv-driver.c and zoran.c, see original files for credits.
+ * 
+ * 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 _MEYE_H_
+#define _MEYE_H_
+
+/****************************************************************************/
+/* Private API for handling mjpeg capture / playback.                       */
+/****************************************************************************/
+
+struct meye_params {
+	unsigned char subsample;
+	unsigned char quality;
+	unsigned char sharpness;
+	unsigned char agc;
+	unsigned char picture;
+	unsigned char framerate;
+};
+
+/* query the extended parameters */
+#define MEYEIOC_G_PARAMS	_IOR ('v', BASE_VIDIOCPRIVATE+0, struct meye_params)
+/* set the extended parameters */
+#define MEYEIOC_S_PARAMS	_IOW ('v', BASE_VIDIOCPRIVATE+1, struct meye_params)
+/* queue a buffer for mjpeg capture */
+#define MEYEIOC_QBUF_CAPT	_IOW ('v', BASE_VIDIOCPRIVATE+2, int)
+/* sync a previously queued mjpeg buffer */
+#define MEYEIOC_SYNC		_IOWR('v', BASE_VIDIOCPRIVATE+3, int)
+/* get a still uncompressed snapshot */
+#define MEYEIOC_STILLCAPT	_IO  ('v', BASE_VIDIOCPRIVATE+4)
+/* get a jpeg compressed snapshot */
+#define MEYEIOC_STILLJCAPT	_IOR ('v', BASE_VIDIOCPRIVATE+5, int)
+
+#endif
diff -u --recursive --new-file v2.4.6/linux/include/linux/nls.h linux/include/linux/nls.h
--- v2.4.6/linux/include/linux/nls.h	Fri May 25 18:01:58 2001
+++ linux/include/linux/nls.h	Mon Jul  9 11:39:39 2001
@@ -1,3 +1,6 @@
+#ifndef _LINUX_NLS_H
+#define _LINUX_NLS_H
+
 #include <linux/init.h>
 
 /* unicode character */
@@ -28,3 +31,6 @@
 extern int utf8_mbstowcs(wchar_t *, const __u8 *, int);
 extern int utf8_wctomb(__u8 *, wchar_t, int);
 extern int utf8_wcstombs(__u8 *, const wchar_t *, int);
+
+#endif /* _LINUX_NLS_H */
+
diff -u --recursive --new-file v2.4.6/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.4.6/linux/include/linux/pci.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/pci.h	Mon Jul  9 11:39:16 2001
@@ -680,13 +680,16 @@
 #if defined(CONFIG_HOTPLUG) && !defined(MODULE)
 	if (rc == 0)
 		return 0;
+#else
+	if (rc == 0)
+		rc = -ENODEV;		
 #endif
 
 	/* if we get here, we need to clean up pci driver instance
 	 * and return some sort of error */
 	pci_unregister_driver (drv);
 	
-	return -ENODEV;
+	return rc;
 }
 
 #endif /* !CONFIG_PCI */
diff -u --recursive --new-file v2.4.6/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.4.6/linux/include/linux/proc_fs.h	Fri May 25 18:01:31 2001
+++ linux/include/linux/proc_fs.h	Mon Jul  9 11:38:58 2001
@@ -171,6 +171,8 @@
 
 #else
 
+#define proc_root_driver NULL
+
 static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, 
 	get_info_t *get_info) {return NULL;}
 static inline void proc_net_remove(const char *name) {}
diff -u --recursive --new-file v2.4.6/linux/include/linux/serialP.h linux/include/linux/serialP.h
--- v2.4.6/linux/include/linux/serialP.h	Fri May 25 18:02:51 2001
+++ linux/include/linux/serialP.h	Mon Jul  9 11:40:31 2001
@@ -142,10 +142,6 @@
  */
 struct pci_dev;
 struct pci_board {
-	unsigned short vendor;
-	unsigned short device;
-	unsigned short subvendor;
-	unsigned short subdevice;
 	int flags;
 	int num_ports;
 	int base_baud;
diff -u --recursive --new-file v2.4.6/linux/include/linux/sonypi.h linux/include/linux/sonypi.h
--- v2.4.6/linux/include/linux/sonypi.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/sonypi.h	Wed Jul  4 14:41:33 2001
@@ -0,0 +1,103 @@
+/* 
+ * Sony Programmable I/O Control Device driver for VAIO
+ *
+ * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * 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 _SONYPI_H_ 
+#define _SONYPI_H_
+
+#include <linux/types.h>
+
+/* events the user application reading /dev/sonypi can use */
+
+#define SONYPI_EVENT_JOGDIAL_DOWN		 1
+#define SONYPI_EVENT_JOGDIAL_UP			 2
+#define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED	 3
+#define SONYPI_EVENT_JOGDIAL_UP_PRESSED		 4
+#define SONYPI_EVENT_JOGDIAL_PRESSED		 5
+#define SONYPI_EVENT_JOGDIAL_RELEASED		 6
+#define SONYPI_EVENT_CAPTURE_PRESSED		 7
+#define SONYPI_EVENT_CAPTURE_RELEASED		 8
+#define SONYPI_EVENT_CAPTURE_PARTIALPRESSED	 9
+#define SONYPI_EVENT_CAPTURE_PARTIALRELEASED	10
+#define SONYPI_EVENT_FNKEY_ESC			11
+#define SONYPI_EVENT_FNKEY_F1			12
+#define SONYPI_EVENT_FNKEY_F2			13
+#define SONYPI_EVENT_FNKEY_F3			14
+#define SONYPI_EVENT_FNKEY_F4			15
+#define SONYPI_EVENT_FNKEY_F5			16
+#define SONYPI_EVENT_FNKEY_F6			17
+#define SONYPI_EVENT_FNKEY_F7			18
+#define SONYPI_EVENT_FNKEY_F8			19
+#define SONYPI_EVENT_FNKEY_F9			20
+#define SONYPI_EVENT_FNKEY_F10			21
+#define SONYPI_EVENT_FNKEY_F11			22
+#define SONYPI_EVENT_FNKEY_F12			23
+#define SONYPI_EVENT_FNKEY_1			24
+#define SONYPI_EVENT_FNKEY_2			25
+#define SONYPI_EVENT_FNKEY_D			26
+#define SONYPI_EVENT_FNKEY_E			27
+#define SONYPI_EVENT_FNKEY_F			28
+#define SONYPI_EVENT_FNKEY_S			29
+#define SONYPI_EVENT_FNKEY_B			30
+#define SONYPI_EVENT_BLUETOOTH_PRESSED		31
+
+/* brightness etc. ioctls */
+#define SONYPI_IOCGBRT	_IOR('v', 0, __u8)
+#define SONYPI_IOCSBRT	_IOW('v', 0, __u8)
+
+#ifdef __KERNEL__
+
+/* used only for communication between v4l and sonypi */
+
+#define SONYPI_COMMAND_GETCAMERA		 1
+#define SONYPI_COMMAND_SETCAMERA		 2
+#define SONYPI_COMMAND_GETCAMERABRIGHTNESS	 3
+#define SONYPI_COMMAND_SETCAMERABRIGHTNESS	 4
+#define SONYPI_COMMAND_GETCAMERACONTRAST	 5
+#define SONYPI_COMMAND_SETCAMERACONTRAST	 6
+#define SONYPI_COMMAND_GETCAMERAHUE		 7
+#define SONYPI_COMMAND_SETCAMERAHUE		 8
+#define SONYPI_COMMAND_GETCAMERACOLOR		 9
+#define SONYPI_COMMAND_SETCAMERACOLOR		10
+#define SONYPI_COMMAND_GETCAMERASHARPNESS	11
+#define SONYPI_COMMAND_SETCAMERASHARPNESS	12
+#define SONYPI_COMMAND_GETCAMERAPICTURE		13
+#define SONYPI_COMMAND_SETCAMERAPICTURE		14
+#define SONYPI_COMMAND_GETCAMERAAGC		15
+#define SONYPI_COMMAND_SETCAMERAAGC		16
+#define SONYPI_COMMAND_GETCAMERADIRECTION	17
+#define SONYPI_COMMAND_GETCAMERAROMVERSION	18
+#define SONYPI_COMMAND_GETCAMERAREVISION	19
+
+u8 sonypi_camera_command(int command, u8 value);
+
+#endif /* __KERNEL__ */
+
+#endif /* _SONYPI_H_ */
diff -u --recursive --new-file v2.4.6/linux/include/linux/spinlock.h linux/include/linux/spinlock.h
--- v2.4.6/linux/include/linux/spinlock.h	Fri May 25 18:01:27 2001
+++ linux/include/linux/spinlock.h	Mon Jul  9 11:38:56 2001
@@ -34,7 +34,8 @@
 #ifdef CONFIG_SMP
 #include <asm/spinlock.h>
 
-#else /* !SMP */
+#elif !defined(spin_lock_init) /* !SMP and spin_lock_init not previously
+                                  defined (e.g. by including asm/spinlock.h */
 
 #define DEBUG_SPINLOCKS	0	/* 0 == no debugging, 1 == maintain lock state, 2 == full debug */
 
diff -u --recursive --new-file v2.4.6/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.4.6/linux/include/linux/swap.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/swap.h	Mon Jul  9 11:38:56 2001
@@ -10,11 +10,23 @@
 
 #define MAX_SWAPFILES 8
 
+/*
+ * Magic header for a swap area. The first part of the union is
+ * what the swap magic looks like for the old (limited to 128MB)
+ * swap area format, the second part of the union adds - in the
+ * old reserved area - some extra information. Note that the first
+ * kilobyte is reserved for boot loader or disk label stuff...
+ *
+ * Having the magic at the end of the PAGE_SIZE makes detecting swap
+ * areas somewhat tricky on machines that support multiple page sizes.
+ * For 2.5 we'll probably want to move the magic to just beyond the
+ * bootbits...
+ */
 union swap_header {
 	struct 
 	{
 		char reserved[PAGE_SIZE - 10];
-		char magic[10];
+		char magic[10];			/* SWAP-SPACE or SWAPSPACE2 */
 	} magic;
 	struct 
 	{
@@ -46,6 +58,9 @@
 #define SWAP_MAP_MAX	0x7fff
 #define SWAP_MAP_BAD	0x8000
 
+/*
+ * The in-memory structure used to track swap areas.
+ */
 struct swap_info_struct {
 	unsigned int flags;
 	kdev_t swap_device;
diff -u --recursive --new-file v2.4.6/linux/include/linux/timex.h linux/include/linux/timex.h
--- v2.4.6/linux/include/linux/timex.h	Fri May 25 18:01:26 2001
+++ linux/include/linux/timex.h	Mon Jul  9 11:38:56 2001
@@ -60,7 +60,9 @@
  * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the
  * nearest power of two in order to avoid hardware multiply operations.
  */
-#if HZ >= 24 && HZ < 48
+#if HZ >= 12 && HZ < 24
+# define SHIFT_HZ	4
+#elif HZ >= 24 && HZ < 48
 # define SHIFT_HZ	5
 #elif HZ >= 48 && HZ < 96
 # define SHIFT_HZ	6
diff -u --recursive --new-file v2.4.6/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.4.6/linux/include/linux/tty.h	Fri May 25 18:01:28 2001
+++ linux/include/linux/tty.h	Mon Jul  9 11:38:57 2001
@@ -366,6 +366,7 @@
 extern int specialix_init(void);
 extern int espserial_init(void);
 extern int macserial_init(void);
+extern int a2232board_init(void);
 
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
 			      const char *routine);
diff -u --recursive --new-file v2.4.6/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.4.6/linux/include/linux/usb.h	Fri May 25 18:02:43 2001
+++ linux/include/linux/usb.h	Mon Jul  9 11:42:23 2001
@@ -838,6 +838,7 @@
 
 extern struct list_head usb_driver_list;
 extern struct list_head usb_bus_list;
+extern rwlock_t usb_bus_list_lock;
 
 /*
  * USB device fs stuff
diff -u --recursive --new-file v2.4.6/linux/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h
--- v2.4.6/linux/include/linux/usbdevice_fs.h	Fri May 25 18:03:10 2001
+++ linux/include/linux/usbdevice_fs.h	Mon Jul  9 11:42:38 2001
@@ -162,18 +162,6 @@
 
 #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) */ 
diff -u --recursive --new-file v2.4.6/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.4.6/linux/include/linux/videodev.h	Tue May 22 10:25:36 2001
+++ linux/include/linux/videodev.h	Wed Jul  4 14:41:33 2001
@@ -375,6 +375,7 @@
 #define VID_HARDWARE_W9966	29
 #define VID_HARDWARE_SE401	30	/* SE401 USB webcams */
 #define VID_HARDWARE_PWC	31	/* Philips webcams */
+#define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.4.6/linux/include/net/irda/ali-ircc.h linux/include/net/irda/ali-ircc.h
--- v2.4.6/linux/include/net/irda/ali-ircc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/ali-ircc.h	Wed Jul  4 11:50:38 2001
@@ -0,0 +1,229 @@
+/*********************************************************************
+ *                
+ * Filename:      ali-ircc.h
+ * Version:       0.5
+ * Description:   Driver for the ALI M1535D and M1543C FIR Controller
+ * Status:        Experimental.
+ * Author:        Benjamin Kong <benjamin_kong@ali.com.tw>
+ * Created at:    2000/10/16 03:46PM
+ * Modified at:   2001/1/3 02:56PM
+ * Modified by:   Benjamin Kong <benjamin_kong@ali.com.tw>
+ * 
+ *     Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw>
+ *     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; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ ********************************************************************/
+
+#ifndef ALI_IRCC_H
+#define ALI_IRCC_H
+
+#include <linux/time.h>
+
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+
+/* SIR Register */
+/* Usr definition of linux/serial_reg.h */
+
+/* FIR Register */
+#define BANK0		0x20
+#define BANK1		0x21
+#define BANK2		0x22
+#define BANK3		0x23
+
+#define FIR_MCR		0x07	/* Master Control Register */
+
+/* Bank 0 */
+#define FIR_DR		0x00	/* Alias 0, FIR Data Register (R/W) */ 
+#define FIR_IER		0x01	/* Alias 1, FIR Interrupt Enable Register (R/W) */
+#define FIR_IIR		0x02	/* Alias 2, FIR Interrupt Identification Register (Read only) */
+#define FIR_LCR_A	0x03	/* Alias 3, FIR Line Control Register A (R/W) */
+#define FIR_LCR_B	0x04	/* Alias 4, FIR Line Control Register B (R/W) */
+#define FIR_LSR		0x05	/* Alias 5, FIR Line Status Register (R/W) */
+#define FIR_BSR		0x06	/* Alias 6, FIR Bus Status Register (Read only) */
+
+
+	/* Alias 1 */
+	#define	IER_FIFO	0x10	/* FIR FIFO Interrupt Enable */	
+	#define	IER_TIMER	0x20 	/* Timer Interrupt Enable */ 
+	#define	IER_EOM		0x40	/* End of Message Interrupt Enable */
+	#define IER_ACT		0x80	/* Active Frame Interrupt Enable */
+	
+	/* Alias 2 */
+	#define IIR_FIFO	0x10	/* FIR FIFO Interrupt */
+	#define IIR_TIMER	0x20	/* Timer Interrupt */
+	#define IIR_EOM		0x40	/* End of Message Interrupt */
+	#define IIR_ACT		0x80	/* Active Frame Interrupt */	
+	
+	/* Alias 3 */
+	#define LCR_A_FIFO_RESET 0x80	/* FIFO Reset */
+
+	/* Alias 4 */
+	#define	LCR_B_BW	0x10	/* Brick Wall */
+	#define LCR_B_SIP	0x20	/* SIP Enable */
+	#define	LCR_B_TX_MODE 	0x40	/* Transmit Mode */
+	#define LCR_B_RX_MODE	0x80	/* Receive Mode */
+	
+	/* Alias 5 */	
+	#define LSR_FIR_LSA	0x00	/* FIR Line Status Address */
+	#define LSR_FRAME_ABORT	0x08	/* Frame Abort */
+	#define LSR_CRC_ERROR	0x10	/* CRC Error */
+	#define LSR_SIZE_ERROR	0x20	/* Size Error */
+	#define LSR_FRAME_ERROR	0x40	/* Frame Error */
+	#define LSR_FIFO_UR	0x80	/* FIFO Underrun */
+	#define LSR_FIFO_OR	0x80	/* FIFO Overrun */
+		
+	/* Alias 6 */
+	#define BSR_FIFO_NOT_EMPTY	0x80	/* FIFO Not Empty */
+	
+/* Bank 1 */
+#define	FIR_CR		0x00 	/* Alias 0, FIR Configuration Register (R/W) */
+#define FIR_FIFO_TR	0x01   	/* Alias 1, FIR FIFO Threshold Register (R/W) */
+#define FIR_DMA_TR	0x02	/* Alias 2, FIR DMA Threshold Register (R/W) */
+#define FIR_TIMER_IIR	0x03	/* Alias 3, FIR Timer interrupt interval register (W/O) */
+#define FIR_FIFO_FR	0x03	/* Alias 3, FIR FIFO Flag register (R/O) */
+#define FIR_FIFO_RAR	0x04 	/* Alias 4, FIR FIFO Read Address register (R/O) */
+#define FIR_FIFO_WAR	0x05	/* Alias 5, FIR FIFO Write Address register (R/O) */
+#define FIR_TR		0x06	/* Alias 6, Test REgister (W/O) */
+
+	/* Alias 0 */
+	#define CR_DMA_EN	0x01	/* DMA Enable */
+	#define CR_DMA_BURST	0x02	/* DMA Burst Mode */
+	#define CR_TIMER_EN 	0x08	/* Timer Enable */
+	
+	/* Alias 3 */
+	#define TIMER_IIR_500	0x00	/* 500 us */
+	#define TIMER_IIR_1ms	0x01	/* 1   ms */
+	#define TIMER_IIR_2ms	0x02	/* 2   ms */
+	#define TIMER_IIR_4ms	0x03	/* 4   ms */
+	
+/* Bank 2 */
+#define FIR_IRDA_CR	0x00	/* Alias 0, IrDA Control Register (R/W) */
+#define FIR_BOF_CR	0x01	/* Alias 1, BOF Count Register (R/W) */
+#define FIR_BW_CR	0x02	/* Alias 2, Brick Wall Count Register (R/W) */
+#define FIR_TX_DSR_HI	0x03	/* Alias 3, TX Data Size Register (high) (R/W) */
+#define FIR_TX_DSR_LO	0x04	/* Alias 4, TX Data Size Register (low) (R/W) */
+#define FIR_RX_DSR_HI	0x05	/* Alias 5, RX Data Size Register (high) (R/W) */
+#define FIR_RX_DSR_LO	0x06	/* Alias 6, RX Data Size Register (low) (R/W) */
+	
+	/* Alias 0 */
+	#define IRDA_CR_HDLC1152 0x80	/* 1.152Mbps HDLC Select */
+	#define IRDA_CR_CRC	0X40	/* CRC Select. */
+	#define IRDA_CR_HDLC	0x20	/* HDLC select. */
+	#define IRDA_CR_HP_MODE 0x10	/* HP mode (read only) */
+	#define IRDA_CR_SD_ST	0x08	/* SD/MODE State.  */
+	#define IRDA_CR_FIR_SIN 0x04	/* FIR SIN Select. */
+	#define IRDA_CR_ITTX_0	0x02	/* SOUT State. IRTX force to 0 */
+	#define IRDA_CR_ITTX_1	0x03	/* SOUT State. IRTX force to 1 */
+	
+/* Bank 3 */
+#define FIR_ID_VR	0x00	/* Alias 0, FIR ID Version Register (R/O) */
+#define FIR_MODULE_CR	0x01	/* Alias 1, FIR Module Control Register (R/W) */
+#define FIR_IO_BASE_HI	0x02	/* Alias 2, FIR Higher I/O Base Address Register (R/O) */
+#define FIR_IO_BASE_LO	0x03	/* Alias 3, FIR Lower I/O Base Address Register (R/O) */
+#define FIR_IRQ_CR	0x04	/* Alias 4, FIR IRQ Channel Register (R/O) */
+#define FIR_DMA_CR	0x05	/* Alias 5, FIR DMA Channel Register (R/O) */
+
+struct ali_chip {
+	char *name;
+	int cfg[2];
+	unsigned char entr1;
+	unsigned char entr2;
+	unsigned char cid_index;
+	unsigned char cid_value;
+	int (*probe)(struct ali_chip *chip, chipio_t *info);
+	int (*init)(struct ali_chip *chip, chipio_t *info); 
+};
+typedef struct ali_chip ali_chip_t;
+
+
+/* DMA modes needed */
+#define DMA_TX_MODE     0x08    /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE     0x04    /* I/O to mem, ++, demand. */
+
+#define MAX_TX_WINDOW 	7
+#define MAX_RX_WINDOW 	7
+
+#define TX_FIFO_Threshold	8
+#define RX_FIFO_Threshold	1
+#define TX_DMA_Threshold	1
+#define RX_DMA_Threshold	1
+
+/* For storing entries in the status FIFO */
+
+struct st_fifo_entry {
+	int status;
+	int len;
+};
+
+struct st_fifo {
+	struct st_fifo_entry entries[MAX_RX_WINDOW];
+	int pending_bytes;
+	int head;
+	int tail;
+	int len;
+};
+
+struct frame_cb {
+	void *start; /* Start of frame in DMA mem */
+	int len;     /* Lenght of frame in DMA mem */
+};
+
+struct tx_fifo {
+	struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
+	int             ptr;                  /* Currently being sent */
+	int             len;                  /* Lenght of queue */
+	int             free;                 /* Next free slot */
+	void           *tail;                 /* Next free start in DMA mem */
+};
+
+/* Private data for each instance */
+struct ali_ircc_cb {
+
+	struct st_fifo st_fifo;    /* Info about received frames */
+	struct tx_fifo tx_fifo;    /* Info about frames to be transmitted */
+
+	struct net_device *netdev;     /* Yes! we are some kind of netdevice */
+	struct net_device_stats stats;
+	
+	struct irlap_cb *irlap;    /* The link layer we are binded to */
+	struct qos_info qos;       /* QoS capabilities for this device */
+	
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+
+	__u8 ier;                  /* Interrupt enable register */
+	
+	__u8 InterruptID;	   /* Interrupt ID */	
+	__u8 BusStatus;		   /* Bus Status */	
+	__u8 LineStatus;	   /* Line Status */	
+	
+	unsigned char rcvFramesOverflow;
+		
+	struct timeval stamp;
+	struct timeval now;
+
+	spinlock_t lock;           /* For serializing operations */
+	
+	__u32 flags;               /* Interface flags */
+	__u32 new_speed;
+	int index;                 /* Instance index */
+	
+	unsigned char fifo_opti_buf;
+
+        struct pm_dev *dev;
+};
+
+static inline void switch_bank(int iobase, int bank)
+{
+		outb(bank, iobase+FIR_MCR);
+}
+
+#endif /* ALI_IRCC_H */
diff -u --recursive --new-file v2.4.6/linux/include/net/irda/irlap.h linux/include/net/irda/irlap.h
--- v2.4.6/linux/include/net/irda/irlap.h	Fri May 25 17:07:20 2001
+++ linux/include/net/irda/irlap.h	Wed Jul  4 11:50:38 2001
@@ -43,15 +43,8 @@
 
 #define LAP_ADDR_HEADER 1  /* IrLAP Address Header */
 #define LAP_CTRL_HEADER 1  /* IrLAP Control Header */
-#define LAP_COMP_HEADER 1  /* IrLAP Compression Header */
 
-#ifdef CONFIG_IRDA_COMPRESSION
-#  define LAP_MAX_HEADER  (LAP_ADDR_HEADER + LAP_CTRL_HEADER + LAP_COMP_HEADER)
-#  define IRDA_COMPRESSED 1
-#  define IRDA_NORMAL     0
-#else
 #define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
-#endif
 
 #define BROADCAST  0xffffffff /* Broadcast device address */
 #define CBROADCAST 0xfe       /* Connection broadcast address */
@@ -68,26 +61,6 @@
 #define NS_UNEXPECTED   0
 #define NS_INVALID     -1
 
-#ifdef CONFIG_IRDA_COMPRESSION
-
-/*  
- *  Just some shortcuts (may give you strange compiler errors if you change 
- *  them :-)
- */
-#define irda_compress    (*self->compessor.cp->compress)
-#define irda_comp_free   (*self->compressor.cp->comp_free)
-#define irda_decompress  (*self->decompressor.cp->decompress)
-#define irda_decomp_free (*self->decompressor.cp->decomp_free)
-#define irda_incomp      (*self->decompressor.cp->incomp)
-
-struct irda_compressor {
-	irda_queue_t q;
-
-	struct compressor *cp;
-	void *state; /* Not used by IrDA */
-};
-#endif
-
 /* Main structure of IrLAP */
 struct irlap_cb {
 	irda_queue_t q;     /* Must be first */
@@ -180,11 +153,6 @@
 	int    xbofs_delay;   /* Nr of XBOF's used to MTT */
 	int    bofs_count;    /* Negotiated extra BOFs */
 	int    next_bofs;     /* Negotiated extra BOFs after next frame */
-
-#ifdef CONFIG_IRDA_COMPRESSION
-	struct irda_compressor compressor;
-        struct irda_compressor decompressor;
-#endif /* CONFIG_IRDA_COMPRESSION */
 };
 
 extern hashbin_t *irlap;
diff -u --recursive --new-file v2.4.6/linux/include/net/irda/irlap_comp.h linux/include/net/irda/irlap_comp.h
--- v2.4.6/linux/include/net/irda/irlap_comp.h	Mon Dec 11 13:33:20 2000
+++ linux/include/net/irda/irlap_comp.h	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlap_comp.h
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Fri Oct  9 09:21:12 1998
- * Modified at:   Sat Dec 12 12:23:16 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998 Dag Brattli, 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; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IRLAP_COMP_H
-#define IRLAP_COMP_H
-
-#include <linux/ppp-comp.h>
-
-#define CI_BZIP2  27 /* Random pick */
-
-extern hashbin_t *irlap_compressors;
-
-int irda_register_compressor( struct compressor *cp);
-void irda_unregister_compressor( struct compressor *cp);
-
-int irda_set_compression( struct irlap_cb *self, int proto);
-void irlap_compressor_init( struct irlap_cb *self, int compress);
-void irda_free_compression( struct irlap_cb *self);
-
-struct sk_buff *irlap_compress_frame( struct irlap_cb *self, 
-				      struct sk_buff *skb);
-struct sk_buff *irlap_decompress_frame( struct irlap_cb *self, 
-					struct sk_buff *skb);
-
-#endif
-
diff -u --recursive --new-file v2.4.6/linux/include/net/irda/qos.h linux/include/net/irda/qos.h
--- v2.4.6/linux/include/net/irda/qos.h	Fri May 25 18:02:38 2001
+++ linux/include/net/irda/qos.h	Mon Jul  9 11:39:42 2001
@@ -43,8 +43,6 @@
 #define PI_ADD_BOFS      0x85
 #define PI_MIN_TURN_TIME 0x86
 #define PI_LINK_DISC     0x08
-#define PI_COMPRESSION   0x07 /* Just a random pick */
-
 
 #define IR_115200_MAX 0x3f
 
@@ -80,10 +78,6 @@
 	qos_value_t link_disc_time;
 	
 	qos_value_t power;
-#ifdef CONFIG_IRDA_COMPRESSION
-	/* An experimental non IrDA field */
-	qos_value_t compression;
-#endif
 };
 
 extern int sysctl_max_baud_rate;
diff -u --recursive --new-file v2.4.6/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.4.6/linux/include/scsi/sg.h	Thu Sep 21 20:48:05 2000
+++ linux/include/scsi/sg.h	Wed Jul  4 15:39:28 2001
@@ -9,89 +9,43 @@
 Original driver (sg.h):
 *       Copyright (C) 1992 Lawrence Foard
 Version 2 and 3 extensions to driver:
-*       Copyright (C) 1998 - 2000 Douglas Gilbert
+*       Copyright (C) 1998 - 2001 Douglas Gilbert
 
-    Version: 3.1.17 (20000921)
+    Version: 3.1.19 (20010623)
     This version is for 2.4 series kernels.
 
-    Changes since 3.1.16 (20000716)
-    	- changes for new scsi subsystem initialization
-    	- change Scsi_Cmnd usage to Scsi_Request
-    	- cleanup for no procfs
-    Changes since 3.1.15 (20000528)
-    	- further (scatter gather) buffer length changes
-    Changes since 3.1.14 (20000503)
-        - fix aha1542 odd length buffer problem
-        - make multiple readers on same fd safe
-    Changes since 3.1.13 (20000324)
-        - revert change so sg_header interface doesn't send _UNKNOWN
-        - "discon" and "tq" in /proc/scsi/sg/devices replaced with
-          "bopens" and "busy"; correct duration output in procfs
-        - provision for SG_RESET
-        - lock file descriptor and request lists
-    Changes since 3.1.12 (20000222)
-    	- make sg_header interface use SCSI_DATA_UNKNOWN
-    	- add SG_DXFER_UNKNOWN define to sg interface
-    	- stop allocating data buffers to non data transfer commands
-    Changes since 3.1.10 (20000123)
-    	- make device allocation dynamic (get rid of SG_EXTRA_DEVS)
-	- move to sg0,sg1,sg2 rather than sga,sgb,sgc
-	- make sg_io_hdr_t safer across architectures
-    Changes since 2.1.34 (990603) and 2.3.35 (990708)
-	- add new interface structure: sg_io_hdr_t
-	  - supports larger sense buffer, DMA residual count + direct IO
-	- add SG_IO ioctl (combines function of write() + read() )
-	- remove SG_SET_MERGE_FD, UNDERRUN_FLAG + _GET_ ioctls + logic
-	- add proc_fs support in /proc/scsi/sg/ directory
-        - add queuing info into struct sg_scsi_id
-	- def_reserved_size can be given at driver or module load time
-    Changes since 2.1.33 (990521)
-        - implement SG_SET_RESERVED_SIZE and associated memory re-org.
-        - add SG_NEXT_CMD_LEN to override SCSI command lengths
-        - add SG_GET_VERSION_NUM to get version expressed as an integer
-    Changes since 2.1.32 (990501)
-        - fix race condition in sg_read() and sg_open()
-    Changes since 2.1.31 (990327)
-        - add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default
-          to _not_ flag underruns (affects aic7xxx driver)
-        - clean up logging of pointers to use %p (for 64 bit architectures)
-        - rework usage of get_user/copy_to_user family of kernel calls
-        - "disown" scsi_command blocks before releasing them
+    Changes since 3.1.18 (20010505)
+	- fix bug that caused long wait when large buffer requested
+	- fix leak in error case of sg_new_read() [report: Eric Barton]
+	- add 'online' column to /proc/scsi/sg/devices
+    Changes since 3.1.17 (20000921)
+    	- add CAP_SYS_RAWIO capability for sensitive stuff
+    	- compile in dio stuff, procfs 'allow_dio' defaulted off (0)
+	- make premature close and detach more robust
+	- lun masked into commands <= SCSI_2
+	- poll() and async notification now yield POLL_HUP on detach
+	- various 3rd party tweaks tracking lk 2.4 internal changes
 
 Map of SG verions to the Linux kernels in which they appear:
        ----------        ----------------------------------
        original          all kernels < 2.2.6
-       2.1.31            2.2.6 and 2.2.7
-       2.1.32            2.2.8 and 2.2.9
-       2.1.34            2.2.10 to 2.2.13
-       2.1.36            2.2.14 and 2.2.15
+       2.1.38            2.2.16
+       2.1.39            2.2.17 - 2.2.19
        3.0.x             optional version 3 sg driver for 2.2 series
-       3.1.x             first appeared in lk 2.3.43
+       3.1.17            2.4.0 ++
 
 Major new features in SG 3.x driver (cf SG 2.x drivers)
 	- SG_IO ioctl() combines function if write() and read()
 	- new interface (sg_io_hdr_t) but still supports old interface
 	- scatter/gather in user space and direct IO supported
 
-Major features in SG 2.x driver (cf original SG driver)
-	- per file descriptor (fd) write-read sequencing
-	- command queuing supported
-	- scatter-gather supported at kernel level allowing potentially
-	  large transfers
-	- more SCSI status information returned
-	- asynchronous notification support added (SIGPOLL, SIGIO)
-	- read() can fetch by given pack_id
-	- uses kernel memory as appropriate for SCSI adapter being used
-	- single SG_BIG_BUFF replaced by per file descriptor "reserve
-	  buffer" whose size can be manipulated by ioctls()
-
  The term "indirect IO" refers a method by which data is DMAed into kernel
  buffers from the hardware and afterwards is transferred into the user
  space (or vice versa if you are writing). Transfer speeds of up to 20 to
  30MBytes/sec have been measured using indirect IO. For faster throughputs
  "direct IO" which cuts out the double handling of data is required.
- Direct IO is supported by the SG 3.x drivers on 2.3 series Linux kernels
- (or later) and requires the use of the new interface.
+ Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels
+ and requires the use of the new interface.
 
  Requests for direct IO with the new interface will automatically fall back
  to indirect IO mode if they cannot be fulfilled. An example of such a case
@@ -107,6 +61,9 @@
  kernel memory that is suitable for DMA may be constrained by the
  architecture of the SCSI adapter (e.g. ISA adapters).
 
+ ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
+         needed. That pseudo file's content is defaulted to 0. **
+
  Documentation
  =============
  A web site for SG device drivers can be found at:
@@ -116,9 +73,10 @@
 	http://www.torque.net/sg/p/scsi-generic_long.txt
  Documentation on the changes and additions in 3.x version of the sg driver
  can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
- This document can also be found in the kernel source tree, probably at:
+ A version of this document (potentially out of date) may also be found in
+ the kernel source tree, probably at:
         /usr/src/linux/Documentation/scsi-generic.txt .
- Utility and test programs are also available at that web site.
+ Utility and test programs are available at the sg web site.
 */
 
 /* New interface introduced in the 3.x SG drivers follows */
diff -u --recursive --new-file v2.4.6/linux/init/main.c linux/init/main.c
--- v2.4.6/linux/init/main.c	Tue Jul  3 17:08:22 2001
+++ linux/init/main.c	Thu Jul  5 11:31:58 2001
@@ -503,6 +503,21 @@
 #endif
 
 /*
+ * We need to finalize in a non-__init function or else race conditions
+ * between the root thread and the init thread may cause start_kernel to
+ * be reaped by free_initmem before the root thread has proceeded to
+ * cpu_idle.
+ */
+
+static void rest_init(void)
+{
+	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	unlock_kernel();
+	current->need_resched = 1;
+ 	cpu_idle();
+} 
+
+/*
  *	Activate the first processor.
  */
  
@@ -523,8 +538,8 @@
 	trap_init();
 	init_IRQ();
 	sched_init();
-	time_init();
 	softirq_init();
+	time_init();
 
 	/*
 	 * HACK ALERT! This is early. We're enabling the console before
@@ -584,10 +599,7 @@
 	 *	make syscalls (and thus be locked).
 	 */
 	smp_init();
-	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
-	unlock_kernel();
-	current->need_resched = 1;
- 	cpu_idle();
+	rest_init();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff -u --recursive --new-file v2.4.6/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.6/linux/kernel/ksyms.c	Tue Jul  3 17:08:22 2001
+++ linux/kernel/ksyms.c	Sun Jul  8 12:52:25 2001
@@ -194,6 +194,7 @@
 EXPORT_SYMBOL(__bforget);
 EXPORT_SYMBOL(ll_rw_block);
 EXPORT_SYMBOL(submit_bh);
+EXPORT_SYMBOL(unlock_buffer);
 EXPORT_SYMBOL(__wait_on_buffer);
 EXPORT_SYMBOL(___wait_on_page);
 EXPORT_SYMBOL(block_write_full_page);
diff -u --recursive --new-file v2.4.6/linux/kernel/sys.c linux/kernel/sys.c
--- v2.4.6/linux/kernel/sys.c	Thu Apr 12 12:20:31 2001
+++ linux/kernel/sys.c	Wed Jul  4 11:50:38 2001
@@ -1119,8 +1119,6 @@
 		return -EINVAL;
 	if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
 		return -EFAULT;
-	if (new_rlim.rlim_cur < 0 || new_rlim.rlim_max < 0)
-		return -EINVAL;
 	old_rlim = current->rlim + resource;
 	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
 	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
diff -u --recursive --new-file v2.4.6/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.6/linux/mm/filemap.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/filemap.c	Mon Jul  9 10:15:06 2001
@@ -1649,10 +1649,13 @@
 {
 	pte_t pte = *ptep;
 
-	if (pte_present(pte) && ptep_test_and_clear_dirty(ptep)) {
+	if (pte_present(pte)) {
 		struct page *page = pte_page(pte);
-		flush_tlb_page(vma, address);
-		set_page_dirty(page);
+		if (VALID_PAGE(page) && !PageReserved(page) && ptep_test_and_clear_dirty(ptep)) {
+			flush_tlb_page(vma, address);
+			if (page->mapping)
+				set_page_dirty(page);
+		}
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.6/linux/mm/memory.c linux/mm/memory.c
--- v2.4.6/linux/mm/memory.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/memory.c	Sun Jul  8 19:20:56 2001
@@ -1108,9 +1108,6 @@
 			spin_lock(&mm->page_table_lock);
 			return -1;
 		}
-		wait_on_page(page);
-		flush_page_to_ram(page);
-		flush_icache_page(vma, page);
 	}
 
 	/*
@@ -1140,6 +1137,8 @@
 		pte = pte_mkwrite(pte_mkdirty(pte));
 	UnlockPage(page);
 
+	flush_page_to_ram(page);
+	flush_icache_page(vma, page);
 	set_pte(page_table, pte);
 
 	/* No need to invalidate - it was non-present before */
diff -u --recursive --new-file v2.4.6/linux/mm/oom_kill.c linux/mm/oom_kill.c
--- v2.4.6/linux/mm/oom_kill.c	Tue May 15 00:25:41 2001
+++ linux/mm/oom_kill.c	Fri Jul  6 17:02:23 2001
@@ -191,11 +191,28 @@
  */
 int out_of_memory(void)
 {
+	long cache_mem, limit;
+
 	/* Enough free memory?  Not OOM. */
 	if (nr_free_pages() > freepages.min)
 		return 0;
 
 	if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low)
+		return 0;
+
+	/*
+	 * If the buffer and page cache (excluding swap cache) are over
+	 * their (/proc tunable) minimum, we're still not OOM.  We test
+	 * this to make sure we don't return OOM when the system simply
+	 * has a hard time with the cache.
+	 */
+	cache_mem = atomic_read(&page_cache_size);
+	cache_mem += atomic_read(&buffermem_pages);
+	cache_mem -= swapper_space.nrpages;
+	limit = (page_cache.min_percent + buffer_mem.min_percent);
+	limit *= num_physpages / 100;
+
+	if (cache_mem > limit)
 		return 0;
 
 	/* Enough swap space left?  Not OOM. */
diff -u --recursive --new-file v2.4.6/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.6/linux/mm/shmem.c	Tue May 22 09:31:25 2001
+++ linux/mm/shmem.c	Mon Jul  9 10:22:08 2001
@@ -223,7 +223,7 @@
  */
 static int shmem_writepage(struct page * page)
 {
-	int error = 0;
+	int error;
 	struct shmem_inode_info *info;
 	swp_entry_t *entry, swap;
 	struct inode *inode;
@@ -231,17 +231,14 @@
 	if (!PageLocked(page))
 		BUG();
 	
-	/* Only move to the swap cache if there are no other users of
-	 * the page. */
-	if (atomic_read(&page->count) > 2)
-		goto out;
-	
 	inode = page->mapping->host;
 	info = &inode->u.shmem_i;
 	swap = __get_swap_page(2);
 	error = -ENOMEM;
-	if (!swap.val)
+	if (!swap.val) {
+		activate_page(page);
 		goto out;
+	}
 
 	spin_lock(&info->lock);
 	entry = shmem_swp_entry(info, page->index);
diff -u --recursive --new-file v2.4.6/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.4.6/linux/mm/swap_state.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/swap_state.c	Sat Jul  7 11:49:13 2001
@@ -81,6 +81,7 @@
 		BUG();
 	flags = page->flags & ~((1 << PG_error) | (1 << PG_arch_1));
 	page->flags = flags | (1 << PG_uptodate);
+	page->age = PAGE_AGE_START;
 	add_to_page_cache_locked(page, &swapper_space, entry.val);
 }
 
diff -u --recursive --new-file v2.4.6/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.4.6/linux/mm/swapfile.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/swapfile.c	Wed Jul  4 11:50:38 2001
@@ -513,7 +513,7 @@
 
 	len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
-		if (ptr->flags & SWP_USED) {
+		if ((ptr->flags & SWP_USED) && ptr->swap_map) {
 			char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
 						page, PAGE_SIZE);
 
diff -u --recursive --new-file v2.4.6/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.4.6/linux/mm/vmscan.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/vmscan.c	Mon Jul  9 10:18:50 2001
@@ -613,7 +613,7 @@
 	 * loads, flush out the dirty pages before we have to wait on
 	 * IO.
 	 */
-	if ((CAN_DO_IO || CAN_DO_FS) && !launder_loop && free_shortage()) {
+	if (CAN_DO_IO && !launder_loop && free_shortage()) {
 		launder_loop = 1;
 		/* If we cleaned pages, never do synchronous IO. */
 		if (cleaned_pages)
diff -u --recursive --new-file v2.4.6/linux/net/atm/mpoa_proc.c linux/net/atm/mpoa_proc.c
--- v2.4.6/linux/net/atm/mpoa_proc.c	Tue May 15 01:29:35 2001
+++ linux/net/atm/mpoa_proc.c	Wed Jul  4 11:50:38 2001
@@ -109,8 +109,6 @@
 	eg_cache_entry *eg_entry;
 	struct timeval now;
 	unsigned char ip_string[16];
-	if(count < 0)
-	        return -EINVAL;
 	if(count == 0)
 	        return 0;
 	page = get_free_page(GFP_KERNEL);
@@ -173,7 +171,6 @@
         char *page, c;
         const char *tmp;
 
-        if (nbytes < 0) return -EINVAL;
         if (nbytes == 0) return 0;
         if (nbytes >= PAGE_SIZE) nbytes = PAGE_SIZE-1;
 
diff -u --recursive --new-file v2.4.6/linux/net/atm/proc.c linux/net/atm/proc.c
--- v2.4.6/linux/net/atm/proc.c	Sun Mar 25 18:14:25 2001
+++ linux/net/atm/proc.c	Wed Jul  4 11:50:38 2001
@@ -495,7 +495,7 @@
 	unsigned long page;
 	int length;
 
-	if (count < 0) return -EINVAL;
+	if (count == 0) return 0;
 	page = get_free_page(GFP_KERNEL);
 	if (!page) return -ENOMEM;
 	dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
@@ -524,7 +524,7 @@
 	info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
 	    ->data;
 
-	if (count < 0) return -EINVAL;
+	if (count == 0) return 0;
 	page = get_free_page(GFP_KERNEL);
 	if (!page) return -ENOMEM;
 	length = (*info)(*pos,(char *) page);
diff -u --recursive --new-file v2.4.6/linux/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- v2.4.6/linux/net/decnet/dn_dev.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_dev.c	Fri Jul  6 16:46:22 2001
@@ -68,106 +68,77 @@
 
 static struct dn_dev_parms dn_dev_list[] =  {
 {
-	ARPHRD_ETHER, /* Ethernet */
-	DN_DEV_BCAST,
-	DN_DEV_S_RU,
-	0,
-	1498,
-	1,
-	10,
-	0,
-	"ethernet",
-	NET_DECNET_CONF_ETHER,
-	dn_eth_up,
-	NULL,
-	dn_send_brd_hello,
-	NULL
+	type:		ARPHRD_ETHER, /* Ethernet */
+	mode:		DN_DEV_BCAST,
+	state:		DN_DEV_S_RU,
+	blksize:	1498,
+	t2:		1,
+	t3:		10,
+	name:		"ethernet",
+	ctl_name:	NET_DECNET_CONF_ETHER,
+	up:		dn_eth_up,
+	timer3:		dn_send_brd_hello,
 },
 {
-	ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
-	DN_DEV_BCAST,
-	DN_DEV_S_RU,
-	0,
-	1400,
-	1,
-	10,
-	0,
-	"ipgre",
-	NET_DECNET_CONF_GRE,
-	NULL,
-	NULL,
-	dn_send_brd_hello,
-	NULL
+	type:		ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
+	mode:		DN_DEV_BCAST,
+	state:		DN_DEV_S_RU,
+	blksize:	1400,
+	t2:		1,
+	t3:		10,
+	name:		"ipgre",
+	ctl_name:	NET_DECNET_CONF_GRE,
+	timer3:		dn_send_brd_hello,
 },
 #if 0
 {
-	ARPHRD_X25, /* Bog standard X.25 */
-	DN_DEV_UCAST,
-	DN_DEV_S_DS,
-	0,
-	230,
-	1,
-	120,
-	0,
-	"x25",
-	NET_DECNET_CONF_X25,
-	NULL,
-	NULL,
-	dn_send_ptp_hello,
-	NULL
+	type:		ARPHRD_X25, /* Bog standard X.25 */
+	mode:		DN_DEV_UCAST,
+	state:		DN_DEV_S_DS,
+	blksize:	230,
+	t2:		1,
+	t3:		120,
+	name:		"x25",
+	ctl_name:	NET_DECNET_CONF_X25,
+	timer3:		dn_send_ptp_hello,
 },
 #endif
 #if 0
 {
-	ARPHRD_PPP, /* DECnet over PPP */
-	DN_DEV_BCAST,
-	DN_DEV_S_RU,
-	0,
-	230,
-	1,
-	10,
-	0,
-	"ppp",
-	NET_DECNET_CONF_PPP,
-	NULL,
-	NULL,
-	dn_send_brd_hello,
-	NULL
+	type:		ARPHRD_PPP, /* DECnet over PPP */
+	mode:		DN_DEV_BCAST,
+	state:		DN_DEV_S_RU,
+	blksize:	230,
+	t2:		1,
+	t3:		10,
+	name:		"ppp",
+	ctl_name:	NET_DECNET_CONF_PPP,
+	timer3:		dn_send_brd_hello,
 },
 #endif
 #if 0
 {
-	ARPHRD_DDCMP, /* DECnet over DDCMP */
-	DN_DEV_UCAST,
-	DN_DEV_S_DS,
-	0,
-	230,
-	1,
-	120,
-	0,
-	"ddcmp",
-	NET_DECNET_CONF_DDCMP,
-	NULL,
-	NULL,
-	dn_send_ptp_hello,
-	NULL
+	type:		ARPHRD_DDCMP, /* DECnet over DDCMP */
+	mode:		DN_DEV_UCAST,
+	state:		DN_DEV_S_DS,
+	blksize:	230,
+	t2:		1,
+	t3:		120,
+	name:		"ddcmp",
+	ctl_name:	NET_DECNET_CONF_DDCMP,
+	timer3:		dn_send_ptp_hello,
 },
 #endif
 {
-	ARPHRD_LOOPBACK, /* Loopback interface - always last */
-	DN_DEV_BCAST,
-	DN_DEV_S_RU,
-	0,
-	1498,
-	1,
-	10,
-	0,
-	"loopback",
-	NET_DECNET_CONF_LOOPBACK,
-	NULL,
-	NULL,
-	dn_send_brd_hello,
-	NULL
+	type:		ARPHRD_LOOPBACK, /* Loopback interface - always last */
+	mode:		DN_DEV_BCAST,
+	state:		DN_DEV_S_RU,
+	blksize:	1498,
+	t2:		1,
+	t3:		10,
+	name:		"loopback",
+	ctl_name:	NET_DECNET_CONF_LOOPBACK,
+	timer3:		dn_send_brd_hello,
 }
 };
 
@@ -182,7 +153,7 @@
 static int min_t3[] = { 1 };
 static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
 
-static int min_priority[] = { 0 };
+static int min_priority[1];
 static int max_priority[] = { 127 }; /* From DECnet spec */
 
 static int dn_forwarding_proc(ctl_table *, int, struct file *,
@@ -344,7 +315,8 @@
 		if (newlen != sizeof(int))
 			return -EINVAL;
 
-		get_user(value, (int *)newval);
+		if (get_user(value, (int *)newval))
+			return -EFAULT;
 		if (value < 0)
 			return -EINVAL;
 		if (value > 2)
diff -u --recursive --new-file v2.4.6/linux/net/decnet/sysctl_net_decnet.c linux/net/decnet/sysctl_net_decnet.c
--- v2.4.6/linux/net/decnet/sysctl_net_decnet.c	Fri Feb  9 11:34:13 2001
+++ linux/net/decnet/sysctl_net_decnet.c	Wed Jul  4 11:50:38 2001
@@ -27,7 +27,7 @@
 #include <net/dn_route.h>
 
 
-int decnet_debug_level = 0;
+int decnet_debug_level;
 int decnet_time_wait = 30;
 int decnet_dn_count = 1;
 int decnet_di_count = 3;
diff -u --recursive --new-file v2.4.6/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c
--- v2.4.6/linux/net/ipv4/netfilter/ip_queue.c	Mon Dec 11 12:37:04 2000
+++ linux/net/ipv4/netfilter/ip_queue.c	Fri Jul  6 17:07:55 2001
@@ -24,19 +24,28 @@
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
+#include <net/route.h>
 
 #include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 
 #define IPQ_QMAX_DEFAULT 1024
 #define IPQ_PROC_FS_NAME "ip_queue"
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
 
+typedef struct ipq_rt_info {
+	__u8 tos;
+	__u32 daddr;
+	__u32 saddr;
+} ipq_rt_info_t;
+
 typedef struct ipq_queue_element {
 	struct list_head list;		/* Links element into queue */
 	int verdict;			/* Current verdict */
 	struct nf_info *info;		/* Extra info from netfilter */
 	struct sk_buff *skb;		/* Packet inside */
+	ipq_rt_info_t rt_info;		/* May need post-mangle routing */
 } ipq_queue_element_t;
 
 typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
@@ -64,7 +73,6 @@
  * Packet queue
  *
  ****************************************************************************/
-
 /* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
 static ipq_queue_element_t *
 ipq_dequeue(ipq_queue_t *q,
@@ -150,9 +158,19 @@
 		printk(KERN_ERR "ip_queue: OOM in enqueue\n");
 		return -ENOMEM;
 	}
+
 	e->verdict = NF_DROP;
 	e->info = info;
 	e->skb = skb;
+
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct iphdr *iph = skb->nh.iph;
+
+		e->rt_info.tos = iph->tos;
+		e->rt_info.daddr = iph->daddr;
+		e->rt_info.saddr = iph->saddr;
+	}
+
 	spin_lock_bh(&q->lock);
 	if (q->len >= *q->maxlen) {
 		spin_unlock_bh(&q->lock);
@@ -198,6 +216,32 @@
 	kfree(q);
 }
 
+/* With a chainsaw... */
+static int route_me_harder(struct sk_buff *skb)
+{
+	struct iphdr *iph = skb->nh.iph;
+	struct rtable *rt;
+
+	struct rt_key key = {
+				dst:iph->daddr, src:iph->saddr,
+				oif:skb->sk ? skb->sk->bound_dev_if : 0,
+				tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+				fwmark:skb->nfmark
+#endif
+			};
+
+	if (ip_route_output_key(&rt, &key) != 0) {
+		printk("route_me_harder: No more route.\n");
+		return -EINVAL;
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+	return 0;
+}
+
 static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
 {
 	int diff;
@@ -223,6 +267,8 @@
 				      "in mangle, dropping packet\n");
 				return -ENOMEM;
 			}
+			if (e->skb->sk)
+				skb_set_owner_w(newskb, e->skb->sk);
 			kfree_skb(e->skb);
 			e->skb = newskb;
 		}
@@ -230,6 +276,19 @@
 	}
 	memcpy(e->skb->data, v->payload, v->data_len);
 	e->skb->nfcache |= NFC_ALTERED;
+
+	/*
+	 * Extra routing may needed on local out, as the QUEUE target never
+	 * returns control to the table.
+	 */
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct iphdr *iph = e->skb->nh.iph;
+
+		if (!(iph->tos == e->rt_info.tos
+		      && iph->daddr == e->rt_info.daddr
+		      && iph->saddr == e->rt_info.saddr))
+			return route_me_harder(e->skb);
+	}
 	return 0;
 }
 
@@ -400,6 +459,13 @@
 	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
 	else pm->outdev_name[0] = '\0';
 	pm->hw_protocol = e->skb->protocol;
+	if (e->info->indev && e->skb->dev) {
+		pm->hw_type = e->skb->dev->type;
+		if (e->skb->dev->hard_header_parse)
+			pm->hw_addrlen =
+				e->skb->dev->hard_header_parse(e->skb,
+				                               pm->hw_addr);
+	}
 	if (data_len)
 		memcpy(pm->payload, e->skb->data, data_len);
 	nlh->nlmsg_len = skb->tail - old_tail;
@@ -431,10 +497,15 @@
 	int status, type;
 	struct nlmsghdr *nlh;
 
+	if (skb->len < sizeof(struct nlmsghdr))
+		return;
+
 	nlh = (struct nlmsghdr *)skb->data;
-	if (nlh->nlmsg_len < sizeof(*nlh)
-	    || skb->len < nlh->nlmsg_len
-	    || nlh->nlmsg_pid <= 0
+	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+	    || skb->len < nlh->nlmsg_len)
+	    	return;
+
+	if(nlh->nlmsg_pid <= 0
 	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
 	    || nlh->nlmsg_flags & NLM_F_MULTI)
 		RCV_SKB_FAIL(-EINVAL);
diff -u --recursive --new-file v2.4.6/linux/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c
--- v2.4.6/linux/net/ipv4/netfilter/ipt_unclean.c	Tue Jul  3 17:08:22 2001
+++ linux/net/ipv4/netfilter/ipt_unclean.c	Fri Jul  6 17:07:55 2001
@@ -268,6 +268,7 @@
 	  int embedded)
 {
 	u_int8_t *opt = (u_int8_t *)tcph;
+	u_int8_t *endhdr = (u_int8_t *)tcph + tcph->doff * 4;
 	u_int8_t tcpflags;
 	int end_of_options = 0;
 	size_t i;
@@ -373,7 +374,7 @@
 				return 0;
 			}
 			/* CHECK: oversize options. */
-			else if (opt[i+1] + i >= tcph->doff * 4) {
+			else if (&opt[i] + opt[i+1] > endhdr) {
 				limpk("TCP option %u at %Zu too long\n",
 				      (unsigned int) opt[i], i);
 				return 0;
@@ -392,6 +393,7 @@
 check_ip(struct iphdr *iph, size_t length, int embedded)
 {
 	u_int8_t *opt = (u_int8_t *)iph;
+	u_int8_t *endhdr = (u_int8_t *)iph + iph->ihl * 4;
 	int end_of_options = 0;
 	void *protoh;
 	size_t datalen;
@@ -444,7 +446,7 @@
 				return 0;
 			}
 			/* CHECK: oversize options. */
-			else if (opt[i+1] + i > iph->ihl * 4) {
+			else if (&opt[i] + opt[i+1] > endhdr) {
 				limpk("IP option %u at %u too long\n",
 				      opt[i], i);
 				return 0;
diff -u --recursive --new-file v2.4.6/linux/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c
--- v2.4.6/linux/net/ipv4/netfilter/iptable_mangle.c	Mon Jan 29 08:07:30 2001
+++ linux/net/ipv4/netfilter/iptable_mangle.c	Fri Jul  6 17:07:55 2001
@@ -148,7 +148,7 @@
 
 	ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
 	/* Reroute for ANY change. */
-	if (ret != NF_DROP && ret != NF_STOLEN
+	if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
 	    && ((*pskb)->nh.iph->saddr != saddr
 		|| (*pskb)->nh.iph->daddr != daddr
 		|| (*pskb)->nfmark != nfmark
diff -u --recursive --new-file v2.4.6/linux/net/irda/Makefile linux/net/irda/Makefile
--- v2.4.6/linux/net/irda/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/net/irda/Makefile	Wed Jul  4 11:50:38 2001
@@ -20,7 +20,6 @@
 obj-m   := $(O_TARGET)
 endif
 
-obj-$(CONFIG_IRDA_COMPRESSION) += irlap_comp.o
 obj-$(CONFIG_PROC_FS) += irproc.o
 obj-$(CONFIG_SYSCTL) += irsysctl.o
 obj-$(CONFIG_IRLAN) += irlan/irlan.o
@@ -28,7 +27,6 @@
 subdir-$(CONFIG_IRLAN) += irlan
 subdir-$(CONFIG_IRNET) += irnet
 subdir-$(CONFIG_IRCOMM) += ircomm
-subdir-$(CONFIG_IRDA_COMPRESSION) += compressors
 
 ifeq ($(CONFIG_IRLAN),y)
 obj-y += irlan/irlan.o
@@ -36,14 +34,6 @@
 
 ifeq ($(CONFIG_IRNET),y)
 obj-y += irnet/irnet.o
-endif
-
-ifeq ($(CONFIG_IRDA_DEFLATE),y)
-obj-y += compressors/irda_deflate.o
-else
-  ifeq ($(CONFIG_IRDA_DEFLATE),m)
-  MOD_TO_LIST += irda_deflate.o
-  endif
 endif
 
 ifeq ($(CONFIG_IRCOMM),y)
diff -u --recursive --new-file v2.4.6/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.4.6/linux/net/irda/af_irda.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/af_irda.c	Wed Jul  4 11:50:38 2001
@@ -218,8 +218,7 @@
 		   self->max_data_size);
 
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
-
-	skb_queue_tail(&sk->receive_queue, skb);
+	kfree_skb(skb);
 
 	/* We are now connected! */
 	sk->state = TCP_ESTABLISHED;
@@ -439,7 +438,7 @@
  * We were waiting for a node to be discovered, but nothing has come up
  * so far. Wake up the user and tell him that we failed...
  */
-static void irda_discovery_timeout(u_long	priv)
+static void irda_discovery_timeout(u_long priv)
 {
 	struct irda_sock *self;
 	
@@ -776,7 +775,6 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
 	struct irda_sock *self;
-	__u16 hints = 0;
 	int err;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -821,15 +819,6 @@
 				 self->stsap_sel, IAS_KERNEL_ATTR);
 	irias_insert_object(self->ias_obj);
 	
-#if 1 /* Will be removed in near future */
-
-	/* Fill in some default hint bits values */
-	if (strncmp(addr->sir_name, "OBEX", 4) == 0)
-		hints = irlmp_service_to_hint(S_OBEX);
-	
-	if (hints)
-		self->skey = irlmp_register_service(hints);
-#endif
 	return 0;
 }
 
@@ -1079,8 +1068,10 @@
 		return -ENOMEM;
 	
 	self = kmalloc(sizeof(struct irda_sock), GFP_ATOMIC);
-	if (self == NULL)
+	if (self == NULL) {
+		kfree (sk);
 		return -ENOMEM;
+	}
 	memset(self, 0, sizeof(struct irda_sock));
 
 	init_waitqueue_head(&self->query_wait);
@@ -1633,34 +1624,58 @@
 {
 	struct sock *sk = sock->sk;
 	unsigned int mask;
+	struct irda_sock *self;
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
+	self = sk->protinfo.irda;
 	poll_wait(file, sk->sleep, wait);
 	mask = 0;
 
-	/* exceptional events? */
+	/* Exceptional events? */
 	if (sk->err)
 		mask |= POLLERR;
-	if (sk->shutdown & RCV_SHUTDOWN)
+	if (sk->shutdown & RCV_SHUTDOWN) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), POLLHUP\n");
 		mask |= POLLHUP;
+	}
 
-	/* readable? */
+	/* Readable? */
 	if (!skb_queue_empty(&sk->receive_queue)) {
 		IRDA_DEBUG(4, "Socket is readable\n");
 		mask |= POLLIN | POLLRDNORM;
 	}
+
 	/* Connection-based need to check for termination and startup */
-	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
-		mask |= POLLHUP;
+	switch (sk->type) {
+	case SOCK_STREAM:
+		if (sk->state == TCP_CLOSE) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), POLLHUP\n");
+			mask |= POLLHUP;
+		}
 
-	/*
-	 * we set writable also when the other side has shut down the
-	 * connection. This prevents stuck sockets.
-	 */
-	if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)
+		if (sk->state == TCP_ESTABLISHED) {
+			if ((self->tx_flow == FLOW_START) && 
+			    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))
+			{
+				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+			}
+		}
+		break;
+	case SOCK_SEQPACKET:
+		if ((self->tx_flow == FLOW_START) && 
+		    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))
+		{	
 			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-
+		}
+		break;
+	case SOCK_DGRAM:
+		if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)
+			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+		break;
+	default:
+		break;
+	}		
 	return mask;
 }
 
@@ -1740,7 +1755,7 @@
 {
  	struct sock *sk = sock->sk;
 	struct irda_sock *self;
-	struct irda_ias_set	ias_opt;
+	struct irda_ias_set    *ias_opt;
 	struct ias_object      *ias_obj;
 	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
 	int opt;
@@ -1763,64 +1778,78 @@
 		if (optlen != sizeof(struct irda_ias_set))
 			return -EINVAL;
 	
+		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
+		if (ias_opt == NULL)
+			return -ENOMEM;
+
 		/* Copy query to the driver. */
-		if (copy_from_user(&ias_opt, (char *)optval, optlen))
+		if (copy_from_user(ias_opt, (char *)optval, optlen)) {
+			kfree(ias_opt);
 		  	return -EFAULT;
+		}
 
 		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt.irda_class_name);
+		ias_obj = irias_find_object(ias_opt->irda_class_name);
 		if(ias_obj == (struct ias_object *) NULL) {
 			/* Create a new object */
-			ias_obj = irias_new_object(ias_opt.irda_class_name,
+			ias_obj = irias_new_object(ias_opt->irda_class_name,
 						   jiffies);
 		}
 
 		/* Do we have it already ? */
-		if(irias_find_attrib(ias_obj, ias_opt.irda_attrib_name))
+		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
+			kfree(ias_opt);
 			return -EINVAL;
+		}
 
 		/* Look at the type */
-		switch(ias_opt.irda_attrib_type) {
+		switch(ias_opt->irda_attrib_type) {
 		case IAS_INTEGER:
 			/* Add an integer attribute */
 			irias_add_integer_attrib(
 				ias_obj,
-				ias_opt.irda_attrib_name, 
-				ias_opt.attribute.irda_attrib_int,
+				ias_opt->irda_attrib_name, 
+				ias_opt->attribute.irda_attrib_int,
 				IAS_USER_ATTR);
 			break;
 		case IAS_OCT_SEQ:
 			/* Check length */
-			if(ias_opt.attribute.irda_attrib_octet_seq.len >
-			   IAS_MAX_OCTET_STRING)
+			if(ias_opt->attribute.irda_attrib_octet_seq.len >
+			   IAS_MAX_OCTET_STRING) {
+				kfree(ias_opt);
 				return -EINVAL;
+			}
 			/* Add an octet sequence attribute */
 			irias_add_octseq_attrib(
 			      ias_obj,
-			      ias_opt.irda_attrib_name, 
-			      ias_opt.attribute.irda_attrib_octet_seq.octet_seq,
-			      ias_opt.attribute.irda_attrib_octet_seq.len,
+			      ias_opt->irda_attrib_name, 
+			      ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
+			      ias_opt->attribute.irda_attrib_octet_seq.len,
 			      IAS_USER_ATTR);
 			break;
 		case IAS_STRING:
 			/* Should check charset & co */
 			/* Check length */
-			if(ias_opt.attribute.irda_attrib_string.len >
-			   IAS_MAX_STRING)
+			if(ias_opt->attribute.irda_attrib_string.len >
+			   IAS_MAX_STRING) {
+				kfree(ias_opt);
 				return -EINVAL;
+			}
 			/* NULL terminate the string (avoid troubles) */
-			ias_opt.attribute.irda_attrib_string.string[ias_opt.attribute.irda_attrib_string.len] = '\0';
+			ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0';
 			/* Add a string attribute */
 			irias_add_string_attrib(
 				ias_obj,
-				ias_opt.irda_attrib_name, 
-				ias_opt.attribute.irda_attrib_string.string,
+				ias_opt->irda_attrib_name, 
+				ias_opt->attribute.irda_attrib_string.string,
 				IAS_USER_ATTR);
 			break;
 		default :
+			kfree(ias_opt);
 			return -EINVAL;
 		}
 		irias_insert_object(ias_obj);
+		kfree(ias_opt);
 		break;
 	case IRLMP_IAS_DEL:
 		/* The user want to delete an object from our local IAS
@@ -1831,31 +1860,42 @@
 		if (optlen != sizeof(struct irda_ias_set))
 			return -EINVAL;
 	
+		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
+		if (ias_opt == NULL)
+			return -ENOMEM;
+	
 		/* Copy query to the driver. */
-		if (copy_from_user(&ias_opt, (char *)optval, optlen))
+		if (copy_from_user(ias_opt, (char *)optval, optlen)) {
+			kfree(ias_opt);
 		  	return -EFAULT;
+		}
 
 		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt.irda_class_name);
-		if(ias_obj == (struct ias_object *) NULL)
+		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		if(ias_obj == (struct ias_object *) NULL) {
+			kfree(ias_opt);
 			return -EINVAL;
+		}
 
 		/* Find the attribute (in the object) we target */
 		ias_attr = irias_find_attrib(ias_obj,
-					     ias_opt.irda_attrib_name); 
-		if(ias_attr == (struct ias_attrib *) NULL)
+					     ias_opt->irda_attrib_name); 
+		if(ias_attr == (struct ias_attrib *) NULL) {
+			kfree(ias_opt);
 			return -EINVAL;
+		}
 
 		/* Check is the user space own the object */
 		if(ias_attr->value->owner != IAS_USER_ATTR) {
 			IRDA_DEBUG(1, __FUNCTION__ 
 				   "(), attempting to delete a kernel attribute\n");
+			kfree(ias_opt);
 			return -EPERM;
 		}
 
 		/* Remove the attribute (and maybe the object) */
 		irias_delete_attrib(ias_obj, ias_attr);
-
+		kfree(ias_opt);
 		break;
 	case IRLMP_MAX_SDU_SIZE:
 		if (optlen < sizeof(int))
@@ -1978,7 +2018,7 @@
 	struct irda_sock *self;
 	struct irda_device_list list;
 	struct irda_device_info *discoveries;
-	struct irda_ias_set	ias_opt;	/* IAS get/query params */
+	struct irda_ias_set *	ias_opt;	/* IAS get/query params */
 	struct ias_object *	ias_obj;	/* Object in IAS */
 	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
 	int daddr = DEV_ADDR_ANY;	/* Dest address for IAS queries */
@@ -2048,34 +2088,49 @@
 		 * that we found */
 
 		/* Check that the user has allocated the right space for us */
-		if (len != sizeof(ias_opt))
+		if (len != sizeof(struct irda_ias_set))
 			return -EINVAL;
 
+		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
+		if (ias_opt == NULL)
+			return -ENOMEM;
+
 		/* Copy query to the driver. */
-		if (copy_from_user((char *) &ias_opt, (char *)optval, len))
+		if (copy_from_user((char *) ias_opt, (char *)optval, len)) {
+			kfree(ias_opt);
 		  	return -EFAULT;
+		}
 
 		/* Find the object we target */
-		ias_obj = irias_find_object(ias_opt.irda_class_name);
-		if(ias_obj == (struct ias_object *) NULL)
+		ias_obj = irias_find_object(ias_opt->irda_class_name);
+		if(ias_obj == (struct ias_object *) NULL) {
+			kfree(ias_opt);
 			return -EINVAL;
+		}
 
 		/* Find the attribute (in the object) we target */
 		ias_attr = irias_find_attrib(ias_obj,
-					     ias_opt.irda_attrib_name); 
-		if(ias_attr == (struct ias_attrib *) NULL)
+					     ias_opt->irda_attrib_name); 
+		if(ias_attr == (struct ias_attrib *) NULL) {
+			kfree(ias_opt);
 			return -EINVAL;
+		}
 
 		/* Translate from internal to user structure */
-		err = irda_extract_ias_value(&ias_opt, ias_attr->value);
-		if(err)
+		err = irda_extract_ias_value(ias_opt, ias_attr->value);
+		if(err) {
+			kfree(ias_opt);
 			return err;
+		}
 
 		/* Copy reply to the user */
-		if (copy_to_user((char *)optval, (char *) &ias_opt,
-				 sizeof(ias_opt)))
+		if (copy_to_user((char *)optval, (char *) ias_opt,
+				 sizeof(struct irda_ias_set))) {
+			kfree(ias_opt);
 		  	return -EFAULT;
+		}
 		/* Note : don't need to put optlen, we checked it */
+		kfree(ias_opt);
 		break;
 	case IRLMP_IAS_QUERY:
 		/* The user want an object from a remote IAS database.
@@ -2083,12 +2138,18 @@
 		 * then wait for the answer to come back. */
 
 		/* Check that the user has allocated the right space for us */
-		if (len != sizeof(ias_opt))
+		if (len != sizeof(struct irda_ias_set))
 			return -EINVAL;
 
+		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
+		if (ias_opt == NULL)
+			return -ENOMEM;
+
 		/* Copy query to the driver. */
-		if (copy_from_user((char *) &ias_opt, (char *)optval, len))
+		if (copy_from_user((char *) ias_opt, (char *)optval, len)) {
+			kfree(ias_opt);
 		  	return -EFAULT;
+		}
 
 		/* At this point, there are two cases...
 		 * 1) the socket is connected - that's the easy case, we
@@ -2105,15 +2166,18 @@
 		} else {
 			/* We are not connected, we must specify a valid
 			 * destination address */
-			daddr = ias_opt.daddr;
-			if((!daddr) || (daddr == DEV_ADDR_ANY))
+			daddr = ias_opt->daddr;
+			if((!daddr) || (daddr == DEV_ADDR_ANY)) {
+				kfree(ias_opt);
 				return -EINVAL;
+			}
 		}
 
 		/* Check that we can proceed with IAP */
 		if (self->iriap) {
 			WARNING(__FUNCTION__
 				"(), busy with a previous query\n");
+			kfree(ias_opt);
 			return -EBUSY;
 		}
 
@@ -2126,14 +2190,15 @@
 		/* Query remote LM-IAS */
 		iriap_getvaluebyclass_request(self->iriap,
 					      self->saddr, daddr,
-					      ias_opt.irda_class_name,
-					      ias_opt.irda_attrib_name);
+					      ias_opt->irda_class_name,
+					      ias_opt->irda_attrib_name);
 		/* Wait for answer (if not already failed) */
 		if(self->iriap != NULL)
 			interruptible_sleep_on(&self->query_wait);
 		/* Check what happened */
 		if (self->errno)
 		{
+			kfree(ias_opt);
 			/* Requested object/attribute doesn't exist */
 			if((self->errno == IAS_CLASS_UNKNOWN) ||
 			   (self->errno == IAS_ATTRIB_UNKNOWN))
@@ -2143,17 +2208,22 @@
 		}
 
 		/* Translate from internal to user structure */
-		err = irda_extract_ias_value(&ias_opt, self->ias_result);
+		err = irda_extract_ias_value(ias_opt, self->ias_result);
 		if (self->ias_result)
 			irias_delete_value(self->ias_result);
-		if (err)
+		if (err) {
+			kfree(ias_opt);
 			return err;
+		}
 
 		/* Copy reply to the user */
-		if (copy_to_user((char *)optval, (char *) &ias_opt,
-				 sizeof(ias_opt)))
+		if (copy_to_user((char *)optval, (char *) ias_opt,
+				 sizeof(struct irda_ias_set))) {
+			kfree(ias_opt);
 		  	return -EFAULT;
+		}
 		/* Note : don't need to put optlen, we checked it */
+		kfree(ias_opt);
 		break;
 	case IRLMP_WAITDEVICE:
 		/* This function is just another way of seeing life ;-)
@@ -2328,6 +2398,9 @@
 SOCKOPS_WRAP(irda_stream, PF_IRDA);
 SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);
 SOCKOPS_WRAP(irda_dgram, PF_IRDA);
+#ifdef CONFIG_IRDA_ULTRA
+SOCKOPS_WRAP(irda_ultra, PF_IRDA);
+#endif /* CONFIG_IRDA_ULTRA */
 
 /*
  * Function irda_device_event (this, event, ptr)
@@ -2416,7 +2489,9 @@
 #endif
 	return 0;
 }
-module_init(irda_proto_init);
+#ifdef MODULE
+module_init(irda_proto_init);	/* If non-module, called from init/main.c */
+#endif
 
 /*
  * Function irda_proto_cleanup (void)
diff -u --recursive --new-file v2.4.6/linux/net/irda/compressors/Config.in linux/net/irda/compressors/Config.in
--- v2.4.6/linux/net/irda/compressors/Config.in	Wed Sep 29 15:32:14 1999
+++ linux/net/irda/compressors/Config.in	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-
-bool '  IrLAP compression' CONFIG_IRDA_COMPRESSION
-
-if [ "$CONFIG_IRDA_COMPRESSION" != "n" ]; then
-   comment '    IrDA compressors'
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_tristate '    Deflate compression (EXPERIMENTAL)' CONFIG_IRDA_DEFLATE $CONFIG_IRDA
-   fi
-#   tristate '    BZIP2 compression' CONFIG_IRDA_BZIP2
-#   tristate '    BSD compression' CONFIG_IRDA_BSD
-fi
diff -u --recursive --new-file v2.4.6/linux/net/irda/compressors/Makefile linux/net/irda/compressors/Makefile
--- v2.4.6/linux/net/irda/compressors/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/net/irda/compressors/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-#
-# Makefile for the Linux IRDA compression protocols
-#
-# 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 definition is now in the main makefile...
-
-O_TARGET :=
-
-obj-y := 
-obj-m := 
-
-obj-$(CONFIG_IRDA_DEFLATE) += irda_deflate.o
-
-include $(TOPDIR)/Rules.make
-
-tar:
-		tar -cvf /dev/f1 .
diff -u --recursive --new-file v2.4.6/linux/net/irda/compressors/irda_deflate.c linux/net/irda/compressors/irda_deflate.c
--- v2.4.6/linux/net/irda/compressors/irda_deflate.c	Fri Feb  9 11:29:44 2001
+++ linux/net/irda/compressors/irda_deflate.c	Wed Dec 31 16:00:00 1969
@@ -1,634 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irda_deflate.c
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Fri Oct  9 02:52:08 1998
- * Modified at:   Mon Dec 14 19:48:54 1998
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *  ==FILEVERSION 980319==
- *
- * irda_deflate.c - interface the zlib procedures for Deflate compression
- * and decompression (as used by gzip) to the IrDA code.
- * This version is for use with Linux kernel 2.1.X.
- *
- * Copyright (c) 1994 The Australian National University.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation is hereby granted, provided that the above copyright
- * notice appears in all copies.  This software is provided without any
- * warranty, express or implied. The Australian National University
- * makes no representations about the suitability of this software for
- * any purpose.
- *
- * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
- * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
- * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
- * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
- * OR MODIFICATIONS.
- *
- * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h> 
-#include <linux/errno.h>
-#include <linux/string.h>	/* used in new tty drivers */
-#include <linux/signal.h>	/* used in new tty drivers */
-
-#include <asm/system.h>
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/inet.h>
-#include <linux/ioctl.h>
-
-#include <linux/ppp_defs.h>
-#include <linux/ppp-comp.h>
-
-/*
- * This is not that nice, but what can we do when the code has been placed
- * elsewhere
- */
-
-#include "../../../drivers/net/zlib.c"
-
-/*
- * State for a Deflate (de)compressor.
- */
-struct irda_deflate_state {
-    int		seqno;
-    int		w_size;
-    int		unit;
-    int		mru;
-    int		debug;
-    z_stream	strm;
-    struct compstat stats;
-};
-
-#define DEFLATE_OVHD	2		/* Deflate overhead/packet */
-
-static void	*zalloc __P((void *, unsigned int items, unsigned int size));
-static void	*zalloc_init __P((void *, unsigned int items,
-				  unsigned int size));
-static void	zfree __P((void *, void *ptr));
-static void	*z_comp_alloc __P((unsigned char *options, int opt_len));
-static void	*z_decomp_alloc __P((unsigned char *options, int opt_len));
-static void	z_comp_free __P((void *state));
-static void	z_decomp_free __P((void *state));
-static int	z_comp_init __P((void *state, unsigned char *options,
-				 int opt_len,
-				 int unit, int hdrlen, int debug));
-static int	z_decomp_init __P((void *state, unsigned char *options,
-				   int opt_len,
-				   int unit, int hdrlen, int mru, int debug));
-static int	z_compress __P((void *state, unsigned char *rptr,
-				unsigned char *obuf,
-				int isize, int osize));
-static void	z_incomp __P((void *state, unsigned char *ibuf, int icnt));
-static int	z_decompress __P((void *state, unsigned char *ibuf,
-				int isize, unsigned char *obuf, int osize));
-static void	z_comp_reset __P((void *state));
-static void	z_decomp_reset __P((void *state));
-static void	z_comp_stats __P((void *state, struct compstat *stats));
-
-struct chunk_header {
-	int valloced;		/* allocated with valloc, not kmalloc */
-	int guard;		/* check for overwritten header */
-};
-
-#define GUARD_MAGIC	0x77a8011a
-#define MIN_VMALLOC	2048	/* use kmalloc for blocks < this */
-
-/*
- * Space allocation and freeing routines for use by zlib routines.
- */
-void zfree(void *arg, void *ptr)
-{
-	struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1;
-	
-	if (hdr->guard != GUARD_MAGIC) {
-		printk(KERN_WARNING "zfree: header corrupted (%x %x) at %p\n",
-		       hdr->valloced, hdr->guard, hdr);
-		return;
-	}
-	if (hdr->valloced)
-		vfree(hdr);
-	else
-		kfree(hdr);
-}
-
-void *
-zalloc(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	hdr = kmalloc(nbytes, GFP_ATOMIC);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = 0;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
-void * zalloc_init(void *arg, unsigned int items, unsigned int size)
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	if (nbytes >= MIN_VMALLOC)
-		hdr = vmalloc(nbytes);
-	else
-		hdr = kmalloc(nbytes, GFP_KERNEL);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = nbytes >= MIN_VMALLOC;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
-static void
-z_comp_free(arg)
-    void *arg;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	if (state) {
-		deflateEnd(&state->strm);
-		kfree(state);
-		MOD_DEC_USE_COUNT;
-	}
-}
-
-/*
- * Allocate space for a compressor.
- */
-static void *
-z_comp_alloc(options, opt_len)
-    unsigned char *options;
-    int opt_len;
-{
-	struct irda_deflate_state *state;
-	int w_size;
-
-	if (opt_len != CILEN_DEFLATE
-	    || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
-	    || options[1] != CILEN_DEFLATE
-	    || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
-	    || options[3] != DEFLATE_CHK_SEQUENCE)
-		return NULL;
-	w_size = DEFLATE_SIZE(options[2]);
-	w_size = MAX_WBITS;
-	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
-		return NULL;
-
-	state = (struct irda_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	MOD_INC_USE_COUNT;
-	memset (state, 0, sizeof (struct irda_deflate_state));
-	state->strm.next_in = NULL;
-	state->strm.zalloc  = zalloc_init;
-	state->strm.zfree   = zfree;
-	state->w_size       = w_size;
-
-	if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
-			 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
-	    != Z_OK)
-		goto out_free;
-	state->strm.zalloc = zalloc;
-	return (void *) state;
-
-out_free:
-	z_comp_free(state);
-	MOD_DEC_USE_COUNT;
-	return NULL;
-}
-
-static int
-z_comp_init(arg, options, opt_len, unit, hdrlen, debug)
-    void *arg;
-    unsigned char *options;
-    int opt_len, unit, hdrlen, debug;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	if (opt_len < CILEN_DEFLATE
-	    || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
-	    || options[1] != CILEN_DEFLATE
-	    || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
-	    || DEFLATE_SIZE(options[2]) != state->w_size
-	    || options[3] != DEFLATE_CHK_SEQUENCE)
-		return 0;
-
-	state->seqno = 0;
-	state->unit  = unit;
-	state->debug = debug;
-
-	deflateReset(&state->strm);
-
-	return 1;
-}
-
-static void z_comp_reset(void *arg)
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	state->seqno = 0;
-	deflateReset(&state->strm);
-}
-
-int
-z_compress(arg, rptr, obuf, isize, osize)
-    void *arg;
-    unsigned char *rptr;	/* uncompressed packet (in) */
-    unsigned char *obuf;	/* compressed packet (out) */
-    int isize, osize;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-	int r, olen, oavail;
-
-	olen = 0;
-
-	/* Don't generate compressed packets which are larger than
-	   the uncompressed packet. */
-	if (osize > isize)
-		osize = isize;
-
-	state->strm.next_out = obuf;
-	state->strm.avail_out = oavail = osize;
-
-	state->strm.next_in = rptr;
-	state->strm.avail_in = isize;
-
-	for (;;) {
-		r = deflate(&state->strm, Z_PACKET_FLUSH);
-		if (r != Z_OK) {
-			if (state->debug)
-				printk(KERN_ERR
-				       "z_compress: deflate returned %d\n", r);
-			break;
-		}
-		if (state->strm.avail_out == 0) {
-			olen += oavail;
-			state->strm.next_out = NULL;
-			state->strm.avail_out = oavail = 1000000;
-		} else {
-			break;		/* all done */
-		}
-	}
-	olen += oavail - state->strm.avail_out;
-
-	/*
-	 * See if we managed to reduce the size of the packet.
-	 */
-	if (olen < isize) {
-		state->stats.comp_bytes += olen;
-		state->stats.comp_packets++;
-	} else {
-		state->stats.inc_bytes += isize;
-		state->stats.inc_packets++;
-		olen = 0;
-	}
-	state->stats.unc_bytes += isize;
-	state->stats.unc_packets++;
-
-	return olen;
-}
-
-static void
-z_comp_stats(arg, stats)
-    void *arg;
-    struct compstat *stats;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	*stats = state->stats;
-}
-
-static void z_decomp_free(void *arg)
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	if (state) {
-		inflateEnd(&state->strm);
-		kfree(state);
-		MOD_DEC_USE_COUNT;
-	}
-}
-
-/*
- * Allocate space for a decompressor.
- */
-static void *
-z_decomp_alloc(options, opt_len)
-    unsigned char *options;
-    int opt_len;
-{
-	struct irda_deflate_state *state;
-	int w_size;
-
-	if (opt_len != CILEN_DEFLATE
-	    || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
-	    || options[1] != CILEN_DEFLATE
-	    || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
-	    || options[3] != DEFLATE_CHK_SEQUENCE)
-		return NULL;
-	w_size = DEFLATE_SIZE(options[2]);
-	w_size = MAX_WBITS;
-	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
-		return NULL;
-
-	state = (struct irda_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	MOD_INC_USE_COUNT;
-	memset (state, 0, sizeof (struct irda_deflate_state));
-	state->w_size        = w_size;
-	state->strm.next_out = NULL;
-	state->strm.zalloc   = zalloc_init;
-	state->strm.zfree    = zfree;
-
-	if (inflateInit2(&state->strm, -w_size) != Z_OK)
-		goto out_free;
-	state->strm.zalloc = zalloc;
-	return (void *) state;
-
-out_free:
-	z_decomp_free(state);
-	MOD_DEC_USE_COUNT;
-	return NULL;
-}
-
-static int
-z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
-    void *arg;
-    unsigned char *options;
-    int opt_len, unit, hdrlen, mru, debug;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	if (opt_len < CILEN_DEFLATE
-	    || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
-	    || options[1] != CILEN_DEFLATE
-	    || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
-	    || DEFLATE_SIZE(options[2]) != state->w_size
-	    || options[3] != DEFLATE_CHK_SEQUENCE)
-		return 0;
-
-	state->seqno = 0;
-	state->unit  = unit;
-	state->debug = debug;
-	state->mru   = mru;
-
-	inflateReset(&state->strm);
-
-	return 1;
-}
-
-static void z_decomp_reset(void *arg)
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-
-	state->seqno = 0;
-	inflateReset(&state->strm);
-}
-
-/*
- * Decompress a Deflate-compressed packet.
- *
- * Because of patent problems, we return DECOMP_ERROR for errors
- * found by inspecting the input data and for system problems, but
- * DECOMP_FATALERROR for any errors which could possibly be said to
- * be being detected "after" decompression.  For DECOMP_ERROR,
- * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
- * infringing a patent of Motorola's if we do, so we take CCP down
- * instead.
- *
- * Given that the frame has the correct sequence number and a good FCS,
- * errors such as invalid codes in the input most likely indicate a
- * bug, so we return DECOMP_FATALERROR for them in order to turn off
- * compression, even though they are detected by inspecting the input.
- */
-int
-z_decompress(arg, ibuf, isize, obuf, osize)
-    void *arg;
-    unsigned char *ibuf;
-    int isize;
-    unsigned char *obuf;
-    int osize;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-	int olen, r;
-	int overflow;
-	unsigned char overflow_buf[1];
-
-	if (isize <= DEFLATE_OVHD) {
-		if (state->debug)
-			printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n",
-			       state->unit, isize);
-		return DECOMP_ERROR;
-	}
-
-	/*
-	 * Set up to call inflate.
-	 */
-	state->strm.next_in = ibuf;
-	state->strm.avail_in = isize;
-	state->strm.next_out = obuf;
-	state->strm.avail_out = osize;
-	overflow = 0;
-
-	/*
-	 * Call inflate, supplying more input or output as needed.
-	 */
-	for (;;) {
-		r = inflate(&state->strm, Z_PACKET_FLUSH);
-		if (r != Z_OK) {
-			if (state->debug)
-				printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
-				       state->unit, r, (state->strm.msg? state->strm.msg: ""));
-			return DECOMP_FATALERROR;
-		}
-		if (state->strm.avail_out != 0)
-			break;		/* all done */
-		
-		if (!overflow) {
-			/*
-			 * We've filled up the output buffer; the only way to
-			 * find out whether inflate has any more characters
-			 * left is to give it another byte of output space.
-			 */
-			state->strm.next_out = overflow_buf;
-			state->strm.avail_out = 1;
-			overflow = 1;
-		} else {
-			if (state->debug)
-				printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
-				       state->unit);
-			return DECOMP_FATALERROR;
-		}
-	}
-
-	olen = osize + overflow - state->strm.avail_out;
-	state->stats.unc_bytes += olen;
-	state->stats.unc_packets++;
-	state->stats.comp_bytes += isize;
-	state->stats.comp_packets++;
-
-	return olen;
-}
-
-/*
- * Incompressible data has arrived - add it to the history.
- */
-static void
-z_incomp(arg, ibuf, icnt)
-    void *arg;
-    unsigned char *ibuf;
-    int icnt;
-{
-	struct irda_deflate_state *state = (struct irda_deflate_state *) arg;
-	int r;
-
-	/*
-	 * Check that the protocol is one we handle.
-	 */
-
-	/*
-	 * We start at the either the 1st or 2nd byte of the protocol field,
-	 * depending on whether the protocol value is compressible.
-	 */
-	state->strm.next_in = ibuf;
-	state->strm.avail_in = icnt;
-
-	r = inflateIncomp(&state->strm);
-	if (r != Z_OK) {
-		/* gak! */
-		if (state->debug) {
-			printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n",
-			       state->unit, r, (state->strm.msg? state->strm.msg: ""));
-		}
-		return;
-	}
-
-	/*
-	 * Update stats.
-	 */
-	state->stats.inc_bytes += icnt;
-	state->stats.inc_packets++;
-	state->stats.unc_bytes += icnt;
-	state->stats.unc_packets++;
-}
-
-/*************************************************************
- * Module interface table
- *************************************************************/
-
-/* These are in ppp.c */
-extern int  irda_register_compressor   (struct compressor *cp);
-extern void irda_unregister_compressor (struct compressor *cp);
-
-/*
- * Procedures exported to if_ppp.c.
- */
-static struct compressor irda_deflate = {
-compress_proto:	CI_DEFLATE,
-comp_alloc:	z_comp_alloc,
-comp_free:	z_comp_free,
-comp_init:	z_comp_init,
-comp_reset:	z_comp_reset,
-compress:	z_compress,
-comp_stat:	z_comp_stats,
-decomp_alloc:	z_decomp_alloc,
-decomp_free:	z_decomp_free,
-decomp_init:	z_decomp_init,
-decomp_reset:	z_decomp_reset,
-decompress:	z_decompress,
-incomp:		z_incomp,
-decomp_stat:	z_comp_stats
-};
-
-static struct compressor irda_deflate_draft = {
-compress_proto:	CI_DEFLATE_DRAFT,
-comp_alloc:	z_comp_alloc,
-comp_free:	z_comp_free,
-comp_init:	z_comp_init,
-comp_reset:	z_comp_reset,
-compress:	z_compress,
-comp_stat:	z_comp_stats,
-decomp_alloc:	z_decomp_alloc,
-decomp_free:	z_decomp_free,
-decomp_init:	z_decomp_init,
-decomp_reset:	z_decomp_reset,
-decompress:	z_decompress,
-incomp:		z_incomp,
-decomp_stat:	z_comp_stats
-};
-
-int __init irda_deflate_init(void)
-{
-        int answer = irda_register_compressor ( &irda_deflate);
-        if (answer == 0)
-                printk (KERN_INFO
-			"IrDA Deflate Compression module registered\n");
-	irda_register_compressor( &irda_deflate_draft);
-        return answer;
-}
-
-void irda_deflate_cleanup(void)
-{
-
-	irda_unregister_compressor (&irda_deflate);
-	irda_unregister_compressor (&irda_deflate_draft);
-}
-
-#ifdef MODULE
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-int init_module(void)
-{  
-	return irda_deflate_init();
-}
-     
-void
-cleanup_module(void)
-{
-	if (MOD_IN_USE)
-		printk (KERN_INFO
-			"Deflate Compression module busy, remove delayed\n");
-	else {
-		irda_deflate_cleanup();
-	}
-}
-#endif
diff -u --recursive --new-file v2.4.6/linux/net/irda/ircomm/ircomm_tty_ioctl.c linux/net/irda/ircomm/ircomm_tty_ioctl.c
--- v2.4.6/linux/net/irda/ircomm/ircomm_tty_ioctl.c	Thu Jan  6 14:46:18 2000
+++ linux/net/irda/ircomm/ircomm_tty_ioctl.c	Wed Jul  4 11:50:38 2001
@@ -221,16 +221,14 @@
 { 
 	unsigned int arg;
 	__u8 old_rts, old_dtr;
-	int error;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-	error = get_user(arg, value);
-	if (error)
-		return error;
+	if (get_user(arg, value))
+		return -EFAULT;
 
 	old_rts = self->settings.dte & IRCOMM_RTS;
 	old_dtr = self->settings.dte & IRCOMM_DTR;
@@ -431,28 +429,18 @@
 		cnow = driver->icount;
 		restore_flags(flags);
 		p_cuser = (struct serial_icounter_struct *) arg;
-		error = put_user(cnow.cts, &p_cuser->cts);
-		if (error) return error;
-		error = put_user(cnow.dsr, &p_cuser->dsr);
-		if (error) return error;
-		error = put_user(cnow.rng, &p_cuser->rng);
-		if (error) return error;
-		error = put_user(cnow.dcd, &p_cuser->dcd);
-		if (error) return error;
-		error = put_user(cnow.rx, &p_cuser->rx);
-		if (error) return error;
-		error = put_user(cnow.tx, &p_cuser->tx);
-		if (error) return error;
-		error = put_user(cnow.frame, &p_cuser->frame);
-		if (error) return error;
-		error = put_user(cnow.overrun, &p_cuser->overrun);
-		if (error) return error;
-		error = put_user(cnow.parity, &p_cuser->parity);
-		if (error) return error;
-		error = put_user(cnow.brk, &p_cuser->brk);
-		if (error) return error;
-		error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
-		if (error) return error;			
+		if (put_user(cnow.cts, &p_cuser->cts) ||
+		    put_user(cnow.dsr, &p_cuser->dsr) ||
+		    put_user(cnow.rng, &p_cuser->rng) ||
+		    put_user(cnow.dcd, &p_cuser->dcd) ||
+		    put_user(cnow.rx, &p_cuser->rx) ||
+		    put_user(cnow.tx, &p_cuser->tx) ||
+		    put_user(cnow.frame, &p_cuser->frame) ||
+		    put_user(cnow.overrun, &p_cuser->overrun) ||
+		    put_user(cnow.parity, &p_cuser->parity) ||
+		    put_user(cnow.brk, &p_cuser->brk) ||
+		    put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+			return -EFAULT;
 #endif		
 		return 0;
 	default:
diff -u --recursive --new-file v2.4.6/linux/net/irda/irias_object.c linux/net/irda/irias_object.c
--- v2.4.6/linux/net/irda/irias_object.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/irias_object.c	Wed Jul  4 11:50:38 2001
@@ -34,7 +34,7 @@
 /*
  *  Used when a missing value needs to be returned
  */
-struct ias_value missing = { IAS_MISSING, 0, 0, 0};
+struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}};
 
 /*
  * Function strdup (str)
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.4.6/linux/net/irda/irlan/irlan_common.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/irlan/irlan_common.c	Wed Jul  4 11:50:38 2001
@@ -209,6 +209,7 @@
 	struct irlan_cb *self;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	ASSERT(irlan != NULL, return NULL;);
 
 	/* 
 	 *  Initialize the irlan structure. 
@@ -224,8 +225,6 @@
 	 */
 	self->magic = IRLAN_MAGIC;
 
-	ASSERT(irlan != NULL, return NULL;);
-	
 	sprintf(self->dev.name, "%s", "unknown");
 
 	self->dev.priv = (void *) self;
@@ -1074,19 +1073,18 @@
 {
  	struct irlan_cb *self;
 	unsigned long flags;
+	ASSERT(irlan != NULL, return 0;);
      
 	save_flags(flags);
 	cli();
 
-	ASSERT(irlan != NULL, return 0;);
-	
 	len = 0;
 	
 	len += sprintf(buf+len, "IrLAN instances:\n");
 	
 	self = (struct irlan_cb *) hashbin_get_first(irlan);
 	while (self != NULL) {
-		ASSERT(self->magic == IRLAN_MAGIC, return len;);
+		ASSERT(self->magic == IRLAN_MAGIC, break;);
 		
 		len += sprintf(buf+len, "ifname: %s,\n",
 			       self->dev.name);
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap.c linux/net/irda/irlap.c
--- v2.4.6/linux/net/irda/irlap.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/irlap.c	Wed Jul  4 11:50:38 2001
@@ -46,7 +46,6 @@
 #include <net/irda/irlap.h>
 #include <net/irda/timer.h>
 #include <net/irda/qos.h>
-#include <net/irda/irlap_comp.h>
 
 hashbin_t *irlap = NULL;
 int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
@@ -79,15 +78,6 @@
 		return -ENOMEM;
 	}
 
-#ifdef CONFIG_IRDA_COMPRESSION
-	irlap_compressors = hashbin_new(HB_LOCAL);
-	if (irlap_compressors == NULL) {
-		WARNING(__FUNCTION__ 
-			"(), can't allocate compressors hashbin!\n");
-		return -ENOMEM;
-	}
-#endif
-
 	return 0;
 }
 
@@ -96,10 +86,6 @@
 	ASSERT(irlap != NULL, return;);
 
 	hashbin_delete(irlap, (FREE_FUNC) __irlap_close);
-
-#ifdef CONFIG_IRDA_COMPRESSION
-	hashbin_delete(irlap_compressors, (FREE_FUNC) kfree);
-#endif
 }
 
 /*
@@ -312,16 +298,6 @@
 	/* Hide LAP header from IrLMP layer */
 	skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
-#ifdef CONFIG_IRDA_COMPRESSION
-	if (self->qos_tx.compression.value) {
-		skb_get(skb); /*LEVEL4*/
-		skb = irlap_decompress_frame(self, skb);
-		if (!skb) {
-			IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
-			return;
-		}
-	}
-#endif
 	skb_get(skb); /*LEVEL4*/
 	irlmp_link_data_indication(self->notify.instance, skb, unreliable);
 }
@@ -341,15 +317,6 @@
 
 	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
-#ifdef CONFIG_IRDA_COMPRESSION
-	if (self->qos_tx.compression.value) {
-		skb = irlap_compress_frame(self, skb);
-		if (!skb) {
-			IRDA_DEBUG(1, __FUNCTION__ "(), Compress error!\n");
-			return;
-		}
-	}
-#endif
 	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
 	       return;);
 	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
@@ -482,9 +449,6 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LAP_MAGIC, return;);
 
-#ifdef CONFIG_IRDA_COMPRESSION
-	irda_free_compression(self);
-#endif
 	/* Flush queues */
 	irlap_flush_all_queues(self);
 	
@@ -860,13 +824,6 @@
 	/* Free sliding window buffered packets */
 	while ((skb = skb_dequeue(&self->wx_list)) != NULL)
 		dev_kfree_skb(skb);
-
-#ifdef CONFIG_IRDA_RECYCLE_RR
-	if (self->recycle_rr_skb) { 
- 		dev_kfree_skb(self->recycle_rr_skb);
- 		self->recycle_rr_skb = NULL;
- 	}
-#endif
 }
 
 /*
@@ -894,50 +851,6 @@
 	}
 }
 
-#ifdef CONFIG_IRDA_COMPRESSION
-void irlap_init_comp_qos_capabilities(struct irlap_cb *self)
-{
-	struct irda_compressor *comp;
-	__u8 mask; /* Current bit tested */
-	int i;
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LAP_MAGIC, return;);
-	
-	/* 
-	 *  Find out which compressors we support. We do this be checking that
-	 *  the corresponding compressor for each bit set in the QoS bits has 
-	 *  actually been loaded. Ths is sort of hairy code but that is what 
-	 *  you get when you do a little bit flicking :-)
-	 */
-	IRDA_DEBUG(4, __FUNCTION__ "(), comp bits 0x%02x\n", 
-		   self->qos_rx.compression.bits); 
-	mask = 0x80; /* Start with testing MSB */
-	for (i=0;i<8;i++) {
-		IRDA_DEBUG(4, __FUNCTION__ "(), testing bit %d\n", 8-i);
-		if (self->qos_rx.compression.bits & mask) {
-			IRDA_DEBUG(4, __FUNCTION__ 
-				   "(), bit %d is set by defalt\n", 8-i);
-			comp = hashbin_find(irlap_compressors, 
-					    compressions[msb_index(mask)], 
-					    NULL);
-			if (!comp) {
-				/* Protocol not supported, so clear the bit */
-				IRDA_DEBUG(4, __FUNCTION__ "(), Compression "
-					   "protocol %d has not been loaded!\n", 
-					   compressions[msb_index(mask)]);
-				self->qos_rx.compression.bits &= ~mask;
-				IRDA_DEBUG(4, __FUNCTION__ 
-					   "(), comp bits 0x%02x\n", 
-					   self->qos_rx.compression.bits); 
-			}
-		}
-		/* Try the next bit */
-		mask >>= 1;
-	}
-}
-#endif	
-
 /*
  * Function irlap_init_qos_capabilities (self, qos)
  *
@@ -956,10 +869,6 @@
 	/* Start out with the maximum QoS support possible */
 	irda_init_max_qos_capabilies(&self->qos_rx);
 
-#ifdef CONFIG_IRDA_COMPRESSION
-	irlap_init_comp_qos_capabilities(self);
-#endif
-
 	/* Apply drivers QoS capabilities */
 	irda_qos_compute_intersection(&self->qos_rx, self->qos_dev);
 
@@ -981,9 +890,6 @@
 
 		if (qos_user->link_disc_time.bits)
 			self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits;
-#ifdef CONFIG_IRDA_COMPRESSION
-		self->qos_rx.compression.bits &= qos_user->compression.bits;
-#endif
 	}
 
 	/* Use 500ms in IrLAP for now */
@@ -1076,7 +982,7 @@
 
 	/* Set the negociated xbofs value */
 	self->next_bofs   = self->qos_tx.additional_bofs.value;
-	if(now)
+	if (now)
 		self->bofs_count = self->next_bofs;
 
 	/* Set the negociated link speed (may need the new xbofs value) */
@@ -1092,51 +998,62 @@
 	self->line_capacity = 
 		irlap_max_line_capacity(self->qos_tx.baud_rate.value,
 					self->qos_tx.max_turn_time.value);
+
+	
+	/* 
+	 *  Initialize timeout values, some of the rules are listed on 
+	 *  page 92 in IrLAP.
+	 */
+	ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
+	ASSERT(self->qos_rx.max_turn_time.value != 0, return;);
+	/* The poll timeout applies only to the primary station.
+	 * It defines the maximum time the primary stay in XMIT mode
+	 * before timeout and turning the link around (sending a RR).
+	 * Or, this is how much we can keep the pf bit in primary mode.
+	 * Therefore, it must be lower or equal than our *OWN* max turn around.
+	 * Jean II */
+	self->poll_timeout = self->qos_tx.max_turn_time.value * HZ / 1000;
+	/* The Final timeout applies only to the primary station.
+	 * It defines the maximum time the primary wait (mostly in RECV mode)
+	 * for an answer from the secondary station before polling it again.
+	 * Therefore, it must be greater or equal than our *PARTNER*
+	 * max turn around time - Jean II */
+	self->final_timeout = self->qos_rx.max_turn_time.value * HZ / 1000;
+	/* The Watchdog Bit timeout applies only to the secondary station.
+	 * It defines the maximum time the secondary wait (mostly in RECV mode)
+	 * for poll from the primary station before getting annoyed.
+	 * Therefore, it must be greater or equal than our *PARTNER*
+	 * max turn around time - Jean II */
+	self->wd_timeout = self->final_timeout * 2;
+
+	/*
+	 * N1 and N2 are maximum retry count for *both* the final timer
+	 * and the wd timer (with a factor 2) as defined above.
+	 * After N1 retry of a timer, we give a warning to the user.
+	 * After N2 retry, we consider the link dead and disconnect it.
+	 * Jean II
+	 */
+
 	/*
 	 *  Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to 
 	 *  3 seconds otherwise. See page 71 in IrLAP for more details.
-	 *  TODO: these values should be calculated from the final timer
-         *  as well
 	 */
-	ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
 	if (self->qos_tx.link_disc_time.value == 3)
 		/* 
 		 * If we set N1 to 0, it will trigger immediately, which is
 		 * not what we want. What we really want is to disable it,
 		 * Jean II 
 		 */
-		self->N1 = -1; /* Disable */
+		self->N1 = -2; /* Disable - Need to be multiple of 2*/
 	else
-		self->N1 = 3000 / self->qos_tx.max_turn_time.value;
+		self->N1 = 3000 / self->qos_rx.max_turn_time.value;
 	
 	IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
 	
-	
+	/* Set N2 to match our own disconnect time */
 	self->N2 = self->qos_tx.link_disc_time.value * 1000 / 
-		self->qos_tx.max_turn_time.value;
+		self->qos_rx.max_turn_time.value;
 	IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
-
-	/* 
-	 *  Initialize timeout values, some of the rules are listed on 
-	 *  page 92 in IrLAP.
-	 */
-	self->poll_timeout = self->qos_tx.max_turn_time.value * HZ / 1000;
-	self->wd_timeout = self->poll_timeout * 2;
-
-	/* 
-	 * Be careful to keep our promises to the peer device about how long
-	 * time it can keep the pf bit. So here we must use the rx_qos value
-	 */
-	self->final_timeout = self->qos_rx.max_turn_time.value * HZ / 1000;
-
-#ifdef CONFIG_IRDA_COMPRESSION
-	if (self->qos_tx.compression.value) {
-		IRDA_DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
-		irda_set_compression(self, self->qos_tx.compression.value);
-
-		irlap_compressor_init(self, 0);
-	}
-#endif
 }
 
 /*
@@ -1226,10 +1143,6 @@
 			       self->qos_tx.min_turn_time.value);
 		len += sprintf(buf+len, "%d\t", 
 			       self->qos_tx.link_disc_time.value);
-#ifdef CONFIG_IRDA_COMPRESSION
-		len += sprintf(buf+len, "%d",
-			       self->qos_tx.compression.value);
-#endif
 		len += sprintf(buf+len, "\n");
 
 		len += sprintf(buf+len, "  rx\t%d\t", 
@@ -1246,10 +1159,6 @@
 			       self->qos_rx.min_turn_time.value);
 		len += sprintf(buf+len, "%d\t", 
 			       self->qos_rx.link_disc_time.value);
-#ifdef CONFIG_IRDA_COMPRESSION
-		len += sprintf(buf+len, "%d",
-			       self->qos_rx.compression.value);
-#endif
 		len += sprintf(buf+len, "\n");
 		
 		self = (struct irlap_cb *) hashbin_get_next(irlap);
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap_comp.c linux/net/irda/irlap_comp.c
--- v2.4.6/linux/net/irda/irlap_comp.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irlap_comp.c	Wed Dec 31 16:00:00 1969
@@ -1,354 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irlap_comp.c
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Fri Oct  9 09:18:07 1998
- * Modified at:   Tue Oct  5 11:34:52 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * Modified at:   Fri May 28  3:11 CST 1999
- * Modified by:   Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
- * Sources:       ppp.c, isdn_ppp.c
- * 
- *     Copyright (c) 1998-1999 Dag Brattli, 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; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#include <linux/string.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irqueue.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlap_comp.h>
-#include "../../drivers/net/zlib.h"
-
-hashbin_t *irlap_compressors = NULL;
-
-/*
- * Function irda_register_compressor (cp)
- *
- *    Register new compressor with the IrLAP
- *
- */
-int irda_register_compressor( struct compressor *cp)
-{
-	struct irda_compressor *new;
-
-	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
-	/* Check if this compressor has been registred before */
-	if ( hashbin_find ( irlap_compressors, cp->compress_proto, NULL)) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), Compressor already registered\n");
-                return 0;
-        }
-	
-	/* Make new IrDA compressor */
-        new = (struct irda_compressor *) 
-		kmalloc( sizeof( struct irda_compressor), GFP_KERNEL);
-        if (new == NULL)
-                return 1;
-		
-	memset( new, 0, sizeof( struct irda_compressor));
-        new->cp = cp;
-
-	/* Insert IrDA compressor into hashbin */
-	hashbin_insert( irlap_compressors, (irda_queue_t *) new, cp->compress_proto,
-			NULL);
-	
-        return 0;
-}
-
-/*
- * Function irda_unregister_compressor (cp)
- *
- *    Unregister compressor
- *
- */
-void irda_unregister_compressor ( struct compressor *cp)
-{
-	struct irda_compressor *node;
-
-	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
-	node = hashbin_remove( irlap_compressors, cp->compress_proto, NULL);
-	if ( !node) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), compressor not found!\n");
-		return;
-	}	
-	kfree( node);
-}
-
-/*
- * Function irda_set_compression (self, proto)
- *
- *    The compression protocol to be used by this session
- *
- */
-int irda_set_compression( struct irlap_cb *self, int proto)
-{
-	struct compressor *cp;
-	struct irda_compressor *comp;
-
-	__u8 options[CILEN_DEFLATE];
-
-	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
-
-	/* Initialize options */
-	options[0] = CI_DEFLATE;
-	options[1] = CILEN_DEFLATE;
-	options[2] = DEFLATE_METHOD( DEFLATE_METHOD_VAL);
-	options[3] = DEFLATE_CHK_SEQUENCE;
-
-	comp = hashbin_find( irlap_compressors, proto, NULL);
-	if ( !comp) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to find compressor\n");
-		return -1;
-	}
-
-	cp = comp->cp;
-	/* 
-	 *  Compressor part
-	 */
-	if ( self->compressor.state != NULL)
-		(*self->compressor.cp->comp_free)( self->compressor.state);
-	self->compressor.state = NULL;
-	
-	self->compressor.cp = cp;
-	self->compressor.state = cp->comp_alloc( options, sizeof( options));
-	if ( self->compressor.state == NULL) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), Failed!\n");
-		return -ENOBUFS;
-	}
-
-	/* 
-	 *  Decompress part
-	 */
-	
-	if ( self->decompressor.state != NULL)
-		irda_decomp_free( self->decompressor.state);
-	self->decompressor.state = NULL;
-	
-	self->decompressor.cp = cp;
-	self->decompressor.state = cp->decomp_alloc( options, sizeof( options));
-	if ( self->decompressor.state == NULL) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), Failed!\n");
-		return -ENOBUFS;
-	}
-	return 0;
-}
-
-/*
- * Function irda_free_compression (self)
- *
- *    
- *
- */
-void irda_free_compression( struct irlap_cb *self)
-{
-	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
-	if ( self->compressor.state) {
-		irda_comp_free( self->compressor.state);
-		self->compressor.state = NULL;
-	}
-	
-	if ( self->decompressor.state) {
-		irda_decomp_free( self->decompressor.state);
-		self->decompressor.state = NULL;
-	}
-}
-
-/*
- * Function irlap_compress_init (self)
- *
- *    
- *
- */
-void irlap_compressor_init( struct irlap_cb *self, int compress)
-{
-	int debug = TRUE;
-	__u8 options[CILEN_DEFLATE];
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	
-	/* Initialize options */
-	options[0] = CI_DEFLATE;
-	options[1] = CILEN_DEFLATE;
-	options[2] = DEFLATE_METHOD_VAL;
-	options[3] = DEFLATE_CHK_SEQUENCE;
-	
-	/*
-	 *  We're agreeing to send compressed packets.
-	 */
-	if ( self->compressor.state == NULL) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), state == NULL\n");
-		return;
-	}
-	
-	if ((*self->compressor.cp->comp_init)( self->compressor.state, 
-					       options, sizeof( options),
-					       0, 0, debug)) 
-	{
-		IRDA_DEBUG( 0, __FUNCTION__ "(), Compressor running!\n");
-		/* ppp->flags |= SC_COMP_RUN; */
-	}
-	
-	/*
-	 *  Initialize decompressor
-	 */
-	if ( self->decompressor.state == NULL) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), state == NULL\n");
-		return;
-	}
-	
-	if (( self->decompressor.cp->decomp_init)( self->decompressor.state,
-						   options, sizeof( options),
-						   0, 0, 0, debug)) 
-	{
-		IRDA_DEBUG( 0, __FUNCTION__ "(), Decompressor running!\n");	
-		
-		/* ppp->flags |= SC_DECOMP_RUN; */
-		/* ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); */
-	}
-}
-
-/*
- * Function irlap_compress_frame (self, skb)
- *
- *
- *
- */
-struct sk_buff *irlap_compress_frame( struct irlap_cb *self, 
-				      struct sk_buff *skb)
-{
-	struct sk_buff *new_skb;
-	int count;
-	
-	ASSERT( skb != NULL, return NULL;);
-	
-	IRDA_DEBUG(4, __FUNCTION__ "() skb->len=%d, jiffies=%ld\n", (int) skb->len,
-	      jiffies);
-
-	ASSERT( self != NULL, return NULL;);
-	ASSERT( self->magic == LAP_MAGIC, return NULL;);
-
-	/* Check if compressor got initialized */
-	if ( self->compressor.state == NULL) {
-		/* Tell peer that this frame is not compressed */
-		skb_push( skb, LAP_COMP_HEADER);
-		skb->data[0] = IRDA_NORMAL;
-
-		return skb;
-	}
-
-	/* FIXME: Find out what is the max overhead (not 10) */
-	new_skb = dev_alloc_skb( skb->len+LAP_MAX_HEADER+10);
-	if(!new_skb)
-		return skb;
-
-	skb_reserve( new_skb, LAP_MAX_HEADER);
-	skb_put( new_skb, skb->len+10);
-	
-	count = (self->compressor.cp->compress)( self->compressor.state, 
-						 skb->data, new_skb->data, 
-						 skb->len, new_skb->len);
-	if( count <= 0) {
-		IRDA_DEBUG(4, __FUNCTION__ "(), Unable to compress frame!\n");
-		dev_kfree_skb( new_skb);
-
-		/* Tell peer that this frame is not compressed */
-		skb_push( skb, 1);
-		skb->data[0] = IRDA_NORMAL;
-
-		return skb;
-	}
-	skb_trim( new_skb, count);
-
-	/* Tell peer that this frame is compressed */
-	skb_push( new_skb, 1);
-	new_skb->data[0] = IRDA_COMPRESSED;
-
-	dev_kfree_skb( skb);
-	
-	IRDA_DEBUG(4, __FUNCTION__ "() new_skb->len=%d\n, jiffies=%ld", 
-	      (int) new_skb->len, jiffies);
-	
-	return new_skb;
-}
-
-/*
- * Function irlap_decompress_frame (self, skb)
- *
- *    
- *
- */
-struct sk_buff *irlap_decompress_frame( struct irlap_cb *self, 
-					struct sk_buff *skb)
-{
-	struct sk_buff *new_skb;
-	int count;
-
-	IRDA_DEBUG( 4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
-
-	ASSERT( self != NULL, return NULL;);
-	ASSERT( self->magic == LAP_MAGIC, return NULL;);
-
-	ASSERT( self->compressor.state != NULL, return NULL;);
-
-	/* Check if frame is compressed */
-	if ( skb->data[0] == IRDA_NORMAL) {
-
-		/* Remove compression header */
-		skb_pull( skb, LAP_COMP_HEADER);
-
-		/*
-		 * The frame is not compressed. Pass it to the
-		 * decompression code so it can update its
-		 * dictionary if necessary.
-		 */
-		irda_incomp( self->decompressor.state, skb->data, skb->len);
-
-		return skb;
-	}
-
-	/* Remove compression header */
-	skb_pull( skb, LAP_COMP_HEADER);
-
-	new_skb = dev_alloc_skb( 2048); /* FIXME: find the right size */
-	if(!new_skb)
-		return skb;
-	skb_put( new_skb, 2048);
-
-	count = irda_decompress( self->decompressor.state, skb->data, 
-				 skb->len, new_skb->data, new_skb->len);
-	if ( count <= 0) {
-		IRDA_DEBUG( 4, __FUNCTION__ "(), Unable to decompress frame!\n");
-		
-		dev_kfree_skb( new_skb);
-		return skb;
-	}
-
-	skb_trim( new_skb, count);
-	
-	IRDA_DEBUG( 4, __FUNCTION__ "() new_skb->len=%d\n", (int) new_skb->len);
-
-	return new_skb;
-}
-
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- v2.4.6/linux/net/irda/irlap_event.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irlap_event.c	Wed Jul  4 11:50:38 2001
@@ -1870,11 +1870,24 @@
 				/* Update Nr received */
 				irlap_update_nr_received(self, info->nr);
 				irlap_wait_min_turn_around(self, &self->qos_tx);
+				irlap_start_wd_timer(self, self->wd_timeout);
 				
-				irlap_send_rr_frame(self, RSP_FRAME);
+				/* Note : if the link is idle (this case),
+				 * we never go in XMIT_S, so we never get a
+				 * chance to process any DISCONNECT_REQUEST.
+				 * Do it now ! - Jean II */
+				if (self->disconnect_pending) {
+					/* Disconnect */
+					irlap_send_rd_frame(self);
+					irlap_flush_all_queues(self);
+
+					irlap_next_state(self, LAP_SCLOSE);
+				} else {
+					/* Just send back pf bit */
+					irlap_send_rr_frame(self, RSP_FRAME);
 				
-				irlap_start_wd_timer(self, self->wd_timeout);
-				irlap_next_state(self, LAP_NRM_S);
+					irlap_next_state(self, LAP_NRM_S);
+				}
 			}
 		} else if (nr_status == NR_UNEXPECTED) {
 			self->remote_busy = FALSE;
@@ -1927,24 +1940,23 @@
 		 *  Wait until retry_count * n matches negotiated threshold/
 		 *  disconnect time (note 2 in IrLAP p. 82)
 		 *
-		 * Note : self->wd_timeout = (self->poll_timeout * 2),
-		 *   and self->final_timeout == self->poll_timeout,
-		 *   which explain why we use (self->retry_count * 2) here !!!
+		 * Note : self->wd_timeout = (self->final_timeout * 2),
+		 *   which explain why we use (self->N2 / 2) here !!!
 		 * Jean II
 		 */
 		IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n", 
 			   self->retry_count);
 
-		if (((self->retry_count * 2) < self->N2)  && 
-		    ((self->retry_count * 2) != self->N1)) {
+		if ((self->retry_count <  (self->N2 / 2))  && 
+		    (self->retry_count != (self->N1 / 2))) {
 			
 			irlap_start_wd_timer(self, self->wd_timeout);
 			self->retry_count++;
-		} else if ((self->retry_count * 2) == self->N1) {
+		} else if (self->retry_count == (self->N1 / 2)) {
 			irlap_status_indication(self, STATUS_NO_ACTIVITY);
 			irlap_start_wd_timer(self, self->wd_timeout);
 			self->retry_count++;
-		} else if ((self->retry_count * 2) >= self->N2) {
+		} else if (self->retry_count >= (self->N2 / 2)) {
 			irlap_apply_default_connection_parameters(self);
 			
 			/* Always switch state before calling upper layers */
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c
--- v2.4.6/linux/net/irda/irlap_frame.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/irlap_frame.c	Wed Jul  4 11:50:38 2001
@@ -742,12 +742,6 @@
 			return;
 		}
 		
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
@@ -788,12 +782,6 @@
 			return;
 		}
 		
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
@@ -863,9 +851,6 @@
 			return;
 		}		
 
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* Insert frame in store */
 		skb_queue_tail(&self->wx_list, skb_get(skb));
 		
@@ -917,9 +902,6 @@
 			return;
 		}		
 		
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* Insert frame in store */
 		skb_queue_tail(&self->wx_list, skb_get(skb));
 		
@@ -973,12 +955,6 @@
 		tx_skb->next = tx_skb->prev = NULL;
 		tx_skb->list = NULL;
 
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
 
@@ -1058,12 +1034,6 @@
 		/* Unlink tx_skb from list */
 		tx_skb->next = tx_skb->prev = NULL;
 		tx_skb->list = NULL;
-
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
 
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlmp.c linux/net/irda/irlmp.c
--- v2.4.6/linux/net/irda/irlmp.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/irlmp.c	Wed Jul  4 11:50:38 2001
@@ -376,7 +376,7 @@
 	 * discovery log and check if any of the links has discovered a
 	 * device with the given daddr 
 	 */
-	if (!saddr) {
+	if ((!saddr) || (saddr == DEV_ADDR_ANY)) {
 		if (daddr != DEV_ADDR_ANY)
 			discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
 		else {
diff -u --recursive --new-file v2.4.6/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- v2.4.6/linux/net/irda/irlmp_event.c	Sat May 19 17:47:55 2001
+++ linux/net/irda/irlmp_event.c	Wed Jul  4 11:50:38 2001
@@ -379,13 +379,23 @@
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 		else {
 			/* No more connections, so close IrLAP */
-			irlmp_next_lap_state(self, LAP_STANDBY);
+
+			/* We don't want to change state just yet, because
+			 * we want to reflect accurately the real state of
+			 * the LAP, not the the state we whish it was in,
+			 * so that we don't loose LM_LAP_CONNECT_REQUEST.
+			 * In some cases, IrLAP won't close the LAP
+			 * immediately. For example, it might still be
+			 * retrying packets or waiting for the pf bit.
+			 * As the LAP always send a DISCONNECT_INDICATION
+			 * in PCLOSE or SCLOSE, just change state on that.
+			 * Jean II */
 			irlap_disconnect_request(self->irlap);
 		}
 		break;
 	case LM_LAP_IDLE_TIMEOUT:
 		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
-			irlmp_next_lap_state(self, LAP_STANDBY);
+			/* Same reasoning as above - keep state */
 			irlap_disconnect_request(self->irlap);
 		}
 		break;
@@ -472,8 +482,6 @@
 		irlmp_start_watchdog_timer(self, 5*HZ);
 		break;
 	case LM_CONNECT_INDICATION:
-		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
-
 		if (self->conn_skb) {
 			WARNING(__FUNCTION__ 
 				"(), busy with another request!\n");
@@ -481,7 +489,20 @@
 		}
 		self->conn_skb = skb;
 
+		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
+
 		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
+
+		/* Start watchdog timer
+		 * This is not mentionned in the spec, but there is a rare
+		 * race condition that can get the socket stuck.
+		 * If we receive this event while our LAP is closing down,
+		 * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in
+		 * CONNECT_PEND state forever.
+		 * Anyway, it make sense to make sure that we always have
+		 * a backup plan. 1 second is plenty (should be immediate).
+		 * Jean II */
+		irlmp_start_watchdog_timer(self, 1*HZ);
 		break;
 	default:
 		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
@@ -533,6 +554,16 @@
 
 		irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
 		break;
+	case LM_WATCHDOG_TIMEOUT:
+		/* May happen, who knows...
+		 * Jean II */
+		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+
+		/* Here, we should probably disconnect proper */
+		self->dlsap_sel = LSAP_ANY;
+		self->conn_skb = NULL;
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
+		break;
 	default:
 		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
 			   irlmp_event[event]);
@@ -563,6 +594,15 @@
 	case LM_CONNECT_REQUEST:
 		/* Keep state */
 		break;
+	case LM_CONNECT_INDICATION:
+		/* Will happen in some rare cases when the socket get stuck,
+		 * the other side retries the connect request.
+		 * We just unstuck the socket - Jean II */
+		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, "
+			   "LSAP stuck in CONNECT_PEND state...\n");
+		/* Keep state */
+		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
+		break;
 	case LM_CONNECT_RESPONSE:
 		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
 			   "no indication issued yet\n");
@@ -581,6 +621,17 @@
 		self->conn_skb = NULL;
 
 		irlmp_connect_indication(self, skb);
+		break;
+	case LM_WATCHDOG_TIMEOUT:
+		/* Will happen in some rare cases because of a race condition.
+		 * Just make sure we don't stay there forever...
+		 * Jean II */
+		IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n");
+
+		/* Go back to disconnected mode, keep the socket waiting */
+		self->dlsap_sel = LSAP_ANY;
+		self->conn_skb = NULL;
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		break;
 	default:
 		IRDA_DEBUG(0, __FUNCTION__ "Unknown event %s\n", 
diff -u --recursive --new-file v2.4.6/linux/net/irda/irproc.c linux/net/irda/irproc.c
--- v2.4.6/linux/net/irda/irproc.c	Sat Nov 27 15:27:49 1999
+++ linux/net/irda/irproc.c	Wed Jul  4 11:50:38 2001
@@ -67,6 +67,8 @@
 	int i;
 
 	proc_irda = proc_mkdir("net/irda", NULL);
+	if (proc_irda == NULL)
+		return;
 	proc_irda->owner = THIS_MODULE;
 
 	for (i=0;i<IRDA_ENTRIES_NUM;i++)
@@ -83,10 +85,13 @@
 {
 	int i;
 
-	for (i=0;i<IRDA_ENTRIES_NUM;i++)
-		remove_proc_entry(dir[i].name, proc_irda);
+        if (proc_irda) {
+                for (i=0;i<IRDA_ENTRIES_NUM;i++)
+                        remove_proc_entry(dir[i].name, proc_irda);
 
-	remove_proc_entry("net/irda", NULL);
+                remove_proc_entry("net/irda", NULL);
+                proc_irda = NULL;
+        }
 }
 
 
diff -u --recursive --new-file v2.4.6/linux/net/irda/irqueue.c linux/net/irda/irqueue.c
--- v2.4.6/linux/net/irda/irqueue.c	Thu Jan  4 13:00:55 2001
+++ linux/net/irda/irqueue.c	Wed Jul  4 11:50:38 2001
@@ -739,7 +739,7 @@
 		/*
 		 * Queue was empty.
 		 */
-	} if ( (*queue)->q_next == *queue ) {
+	} else if ( (*queue)->q_next == *queue ) {
 		/* 
 		 *  Queue only contained a single element. It will now be
 		 *  empty.  
diff -u --recursive --new-file v2.4.6/linux/net/irda/irsyms.c linux/net/irda/irsyms.c
--- v2.4.6/linux/net/irda/irsyms.c	Sun Nov 12 20:43:11 2000
+++ linux/net/irda/irsyms.c	Wed Jul  4 11:50:38 2001
@@ -35,9 +35,6 @@
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irlap.h>
-#ifdef CONFIG_IRDA_COMPRESSION
-#include <net/irda/irlap_comp.h>
-#endif /* CONFIG_IRDA_COMPRESSION */
 #include <net/irda/irlmp.h>
 #include <net/irda/iriap.h>
 #include <net/irda/irias_object.h>
@@ -66,12 +63,6 @@
 extern int irlpt_client_init(void);
 extern int irlpt_server_init(void);
 
-#ifdef CONFIG_IRDA_COMPRESSION
-#ifdef CONFIG_IRDA_DEFLATE
-extern irda_deflate_init();
-#endif /* CONFIG_IRDA_DEFLATE */
-#endif /* CONFIG_IRDA_COMPRESSION */
-
 /* IrTTP */
 EXPORT_SYMBOL(irttp_open_tsap);
 EXPORT_SYMBOL(irttp_close_tsap);
@@ -150,10 +141,6 @@
 /* IrLAP */
 EXPORT_SYMBOL(irlap_open);
 EXPORT_SYMBOL(irlap_close);
-#ifdef CONFIG_IRDA_COMPRESSION
-EXPORT_SYMBOL(irda_unregister_compressor);
-EXPORT_SYMBOL(irda_register_compressor);
-#endif /* CONFIG_IRDA_COMPRESSION */
 EXPORT_SYMBOL(irda_init_max_qos_capabilies);
 EXPORT_SYMBOL(irda_qos_bits_to_value);
 EXPORT_SYMBOL(irda_device_setup);
@@ -208,13 +195,6 @@
 	ircomm_init();
 	ircomm_tty_init();
 #endif
-
-#ifdef CONFIG_IRDA_COMPRESSION
-#ifdef CONFIG_IRDA_DEFLATE
-	irda_deflate_init();
-#endif /* CONFIG_IRDA_DEFLATE */
-#endif /* CONFIG_IRDA_COMPRESSION */
-
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.6/linux/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- v2.4.6/linux/net/irda/irsysctl.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/irsysctl.c	Wed Jul  4 11:50:38 2001
@@ -32,7 +32,7 @@
 #include <net/irda/irias_object.h>
 
 #define NET_IRDA 412 /* Random number */
-enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, DISCOVERY_TIMEOUT, 
+enum { DISCOVERY=1, DEVNAME, DEBUG, SLOTS, DISCOVERY_TIMEOUT, 
        SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME };
 
 extern int  sysctl_discovery;
@@ -71,8 +71,6 @@
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ DEVNAME, "devname", sysctl_devname,
 	  65, 0644, NULL, &do_devname, &sysctl_string},
-	{ COMPRESSION, "compression", &sysctl_compression,
-	  sizeof(int), 0644, NULL, &proc_dointvec },
 #ifdef CONFIG_IRDA_DEBUG
         { DEBUG, "debug", &irda_debug,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
diff -u --recursive --new-file v2.4.6/linux/net/irda/irttp.c linux/net/irda/irttp.c
--- v2.4.6/linux/net/irda/irttp.c	Tue May  1 16:05:00 2001
+++ linux/net/irda/irttp.c	Wed Jul  4 11:50:38 2001
@@ -1598,7 +1598,7 @@
 	self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps);
 	while (self != NULL) {
 		if (!self || self->magic != TTP_TSAP_MAGIC)
-			return len;
+			break;
 
 		len += sprintf(buf+len, "TSAP %d, ", i++);
 		len += sprintf(buf+len, "stsap_sel: %02x, ", 
diff -u --recursive --new-file v2.4.6/linux/net/irda/qos.c linux/net/irda/qos.c
--- v2.4.6/linux/net/irda/qos.c	Mon Apr 30 16:26:09 2001
+++ linux/net/irda/qos.c	Wed Jul  4 11:50:38 2001
@@ -36,12 +36,6 @@
 #include <net/irda/parameters.h>
 #include <net/irda/qos.h>
 #include <net/irda/irlap.h>
-#ifdef CONFIG_IRDA_COMPRESSION
-#include <net/irda/irlap_comp.h>
-#include "../../drivers/net/zlib.h"
-
-#define CI_BZIP2  27 /* Random pick */
-#endif
 
 /*
  * Maximum values of the baud rate we negociate with the other end.
@@ -79,10 +73,6 @@
 __u32 max_turn_times[]  = { 500, 250, 100, 50 };                    /* ms */
 __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 };         /* secs */
 
-#ifdef CONFIG_IRDA_COMPRESSION
-__u32 compressions[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
-#endif
-
 __u32 max_line_capacities[10][4] = {
        /* 500 ms     250 ms  100 ms  50 ms (max turn time) */
 	{    100,      0,      0,     0 }, /*     2400 bps */
@@ -238,10 +228,6 @@
 	qos->link_disc_time.bits  &= new->link_disc_time.bits;
 	qos->additional_bofs.bits &= new->additional_bofs.bits;
 
-#ifdef CONFIG_IRDA_COMPRESSION
-	qos->compression.bits     &= new->compression.bits;
-#endif
-
 	irda_qos_bits_to_value(qos);
 }
 
@@ -280,10 +266,6 @@
 	qos->data_size.bits       = 0x3f;
 	qos->link_disc_time.bits &= 0xff;
 	qos->additional_bofs.bits = 0xff;
-
-#ifdef CONFIG_IRDA_COMPRESSION	
-	qos->compression.bits     = 0x03;
-#endif
 }
 
 /*
@@ -359,20 +341,10 @@
 int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) 
 {
 	int ret;
-#ifdef CONFIG_IRDA_COMPRESSION
-	int comp_seen = FALSE;
-#endif
+	
 	ret = irda_param_extract_all(self, skb->data, skb->len, 
 				     &irlap_param_info);
 	
-#ifdef CONFIG_IRDA_COMPRESSION
-	if (!comp_seen) {
-		IRDA_DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n");
-		self->qos_tx.compression.bits = 0x00;
-		self->qos_rx.compression.bits = 0x00;
-	}
-#endif
-
 	/* Convert the negotiated bits to values */
 	irda_qos_bits_to_value(&self->qos_tx);
 	irda_qos_bits_to_value(&self->qos_rx);
@@ -393,10 +365,6 @@
 		   self->qos_tx.min_turn_time.value);
 	IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n", 
 		   self->qos_tx.link_disc_time.value);
-#ifdef CONFIG_IRDA_COMPRESSION
-	IRDA_DEBUG(2, "Setting COMPRESSION to %d\n", 
-		   self->qos_tx.compression.value);
-#endif	
 	return ret;
 }
 
@@ -710,12 +678,4 @@
 	
 	index = msb_index(qos->additional_bofs.bits);
 	qos->additional_bofs.value = add_bofs[index];
-
-#ifdef CONFIG_IRDA_COMPRESSION
-	index = msb_index(qos->compression.bits);
-	if (index >= 0)
-		qos->compression.value = compressions[index];
-	else 
-		qos->compression.value = 0;
-#endif
 }
diff -u --recursive --new-file v2.4.6/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.4.6/linux/net/sunrpc/svcsock.c	Fri Apr 27 14:15:01 2001
+++ linux/net/sunrpc/svcsock.c	Wed Jul  4 11:50:38 2001
@@ -383,7 +383,7 @@
 
 	/* Sorry. */
 	if (skb_is_nonlinear(skb)) {
-		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+		if (skb_linearize(skb, GFP_KERNEL) != 0) {
 			kfree_skb(skb);
 			svc_sock_received(svsk, 0);
 			return 0;
